juicedata/juicefs · critical

The entry of the root inode was not found

Error message

The entry of the root inode was not found

What it means

During kvMeta.Load (V1 dump-format loading) in the TKV metadata engine, the code looks up the entry for root inode 1; if the tree record is missing or has no Attr, it refuses to continue. This means the loaded snapshot is not a valid JuiceFS metadata tree (root inode absent) or the load was given a malformed/empty key-range.

Source

Thrown at pkg/meta/tkv.go:4097

		}
		if err = m.dumpEntry(root, tree, nil); err != nil {
			return err
		}
		if root == RootInode && !skipTrash {
			trash = &DumpedEntry{
				Attr: &DumpedAttr{
					Inode: TrashInode,
					Type:  "directory",
				},
			}
			if err = m.dumpEntry(TrashInode, trash, nil); err != nil {
				return err
			}
		}
	}

	if tree == nil || tree.Attr == nil {
		return errors.New("The entry of the root inode was not found")
	}
	tree.Name = "FSTree"

	var rs [][]byte
	err = m.txn(Background(), func(tx *kvTxn) error {
		rs = tx.gets(m.counterKey(usedSpace),
			m.counterKey(totalInodes),
			m.counterKey("nextInode"),
			m.counterKey("nextChunk"),
			m.counterKey("nextSession"),
			m.counterKey("nextTrash"))
		return nil
	})
	if err != nil {
		return err
	}
	cs := make([]int64, len(rs))
	for i, r := range rs {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Verify the backup file is a complete, unmodified juicefs dump that contains the root inode (inode 1) entry; re-dump from the source volume if it was truncated.
  2. Check the dump/load filter options (paths/inode ranges) — ensure the load actually includes the FSTree/root entry instead of a partial subtree.
  3. Confirm dump/load format compatibility between the client versions producing and consuming the backup; upgrade the loading client if the dump is from a newer version.
  4. If the target engine is not empty, check for conflicting partial loads; wipe the target and retry with a verified backup.

Example fix

// before (loading a filtered backup that dropped root)
juicefs load redis://127.0.0.1:6379/1 partial.dump
// after (verify root entry exists, then load full backup)
grep -m1 '"inode":1' full.dump
juicefs load redis://127.0.0.1:6379/1 full.dump
Defensive patterns

Strategy: validation

Validate before calling

import "encoding/json"
func backupHasRootInode(dump []byte) bool {
    for _, line := range bytes.Split(dump, []byte("\n")) {
        var rec struct{ Inode Ino `json:"inode"` }
        if json.Unmarshal(line, &rec) == nil && rec.Inode == 1 {
            return true
        }
    }
    return false
}

Prevention

When it happens

Trigger: Calling juicefs load (kvMeta.Load) against a backup file that lacks the root inode (inode 1) entry, loading a corrupted or truncated dump, or loading data dumped with an incompatible/older format into a TKV engine (TiKV/etcd/Badger/FoundationDB).

Common situations: Restoring a manually edited or partially copied backup; loading a dump produced from a different tool/format; mixing versions where the dump predates fields the loader requires; loading into an empty engine from a file whose tree segment was lost.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/208598fc1b3be2ec. Report an issue: GitHub.