lima-vm/lima · error

expected B-tree node type (2 or 3), got %#x

Error message

expected B-tree node type (2 or 3), got %#x

What it means

verifyBTreeNodeType validates that a block's object type field (masked) is OBJECT_TYPE_BTREE (0x02) or OBJECT_TYPE_BTREE_NODE (0x03). This is the root cause message wrapped by callers as 'omap node: %w' or 'filesystem B-tree node: %w'. It indicates the parser followed a pointer to a block that is not a B-tree node, i.e. on-disk structure differs from what the parser expects.

Source

Thrown at pkg/apfs/chown.go:397

// For fixed-KV nodes (kvoff_t): 4 bytes per entry (k_off u16, v_off u16).
// For variable-KV nodes (kvloc_t): 8 bytes per entry (k.off u16, k.len u16, v.off u16, v.len u16).
// Returns keyOffset and valueOffset (both relative to their respective areas).
func (c *container) readTocEntry(blk []byte, tocStart, index uint32, fixedKV bool) (keyOff, valOff uint32) {
	if fixedKV {
		off := tocStart + index*4
		return uint32(le.Uint16(blk[off:])), uint32(le.Uint16(blk[off+2:]))
	}
	off := tocStart + index*8
	return uint32(le.Uint16(blk[off:])), uint32(le.Uint16(blk[off+4:]))
}

// verifyBTreeNodeType checks that a block's object type indicates a
// B-tree node: OBJECT_TYPE_BTREE (0x02, root) or OBJECT_TYPE_BTREE_NODE
// (0x03, non-root).
func verifyBTreeNodeType(blk []byte) error {
	oType := le.Uint32(blk[objTypeOff:]) & objTypeMask
	if oType != 0x02 && oType != 0x03 {
		return fmt.Errorf("expected B-tree node type (2 or 3), got %#x", oType)
	}
	return nil
}

func compareOmapKey(oid1, xid1, oid2, xid2 uint64) int {
	if oid1 < oid2 {
		return -1
	}
	if oid1 > oid2 {
		return 1
	}
	if xid1 < xid2 {
		return -1
	}
	if xid1 > xid2 {
		return 1
	}
	return 0

View on GitHub (pinned to dd909d0973)

Solutions

  1. Confirm the APFS container's block size (parser assumes standard offsets; test with a 4096-byte-block image).
  2. Run fsck_apfs from a macOS host and retry on the repaired image.
  3. Re-copy the image from a cleanly shut-down VM to rule out corruption.
  4. Check whether the image comes from a macOS version with on-disk format changes unsupported by this parser.
  5. Verify you are not reading the wrong region (e.g. non-APFS partition) as a B-tree.
Defensive patterns

Strategy: type-guard

Validate before calling

// Pre-flight: ensure the image is a raw APFS container with a plausible block size.
info, err := os.Stat(diskPath)
if err != nil { return err }
if info.Size() == 0 || info.Size()%4096 != 0 {
	return errors.New("image size is not block-aligned; wrong file format?")
}

Try / catch

if err := apfs.Chown(diskPath, role, uid, gid, paths...); err != nil {
	if strings.Contains(err.Error(), "expected B-tree node type") {
		return fmt.Errorf("unsupported or corrupt APFS layout in %s: %w", diskPath, err)
	}
	return err
}

Prevention

When it happens

Trigger: Following a corrupt child pointer, applying fixed offsets to an image with an unexpected block size, or parsing an APFS variant/newer format where the type constants or layout differ.

Common situations: Very new or unusual macOS images, wrong disk image (non-APFS region interpreted as a tree), corrupted metadata, or parser constant mismatches with large block-size (8K/16K) containers.

Related errors


AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01). Data as JSON: /api/errors/ec0061b414877ce3. Report an issue: GitHub.