lima-vm/lima · critical

reading omap child node

Error message

reading omap child node: %w

What it means

During descent through an internal omap B-tree node, omapLookup reads the child node at the physical address stored in the child pointer. This error wraps the readBlock failure for that child, meaning an I/O-level failure (typically EOF because the address lies past the end of the image) occurred before checksum or type validation could run.

Solutions

  1. Verify the image file size matches the source disk; re-copy if truncated.
  2. Run fsck_apfs on the image from a macOS host to repair B-tree structure.
  3. Re-export the image from a cleanly shut-down VM.
  4. Check host disk health if I/O errors persist.
  5. Restore from backup if corruption is confirmed.
Defensive patterns

Strategy: try-catch

Try / catch

if err := apfs.Chown(diskPath, role, uid, gid, paths...); err != nil {
	if strings.Contains(err.Error(), "reading omap child node") {
		return fmt.Errorf("omap tree is inconsistent or the image is truncated: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: A corrupt or dangling child pointer inside an internal omap node, an image truncated so the child block is missing, or I/O errors reading that region of the disk file.

Common situations: Truncated/partial disk copies, images from crashed or still-running VMs with inconsistent trees, bad host storage, or corrupted images after an interrupted file transfer.

Related errors


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

Appendix: source

Thrown at pkg/apfs/chown.go:373

			keyStart := keyAreaStart + kOff
			entryOID := le.Uint64(blk[keyStart:])
			entryXID := le.Uint64(blk[keyStart+8:])

			cmp := compareOmapKey(entryOID, entryXID, oid, maxXID)
			if cmp <= 0 {
				childIdx = i
			} else {
				break
			}
		}

		// Read child pointer (physical address, 8 bytes).
		_, vOff := c.readTocEntry(blk, tocStart, childIdx, isFixedKV)
		childAddr := le.Uint64(blk[valueAreaEnd-vOff:])

		blk, err = c.readBlock(childAddr)
		if err != nil {
			return 0, fmt.Errorf("reading omap child node: %w", err)
		}
	}
}

// readTocEntry reads the key and value offsets from a ToC entry.
// 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

View on GitHub (pinned to dd909d0973)