lima-vm/lima · error

read block 0: %w

Error message

read block 0: %w

What it means

Thrown by openContainer when f.ReadAt(hdr, 0) cannot read the first 4096 bytes of the disk image — the region that must contain either the NX (container) superblock magic or a GPT protective structures. The underlying read error (short/empty file returning io.EOF, I/O error, device error) is wrapped as "read block 0".

Source

Thrown at pkg/apfs/chown.go:75

// volumeInfo holds resolved volume information.
type volumeInfo struct {
	omapTreeAddr uint64 // physical address of volume omap B-tree root
	rootTreeOID  uint64 // virtual OID of filesystem B-tree root
	latestXID    uint64 // transaction ID of the volume superblock
}

func openContainer(path string) (*container, error) {
	f, err := os.OpenFile(path, os.O_RDWR, 0)
	if err != nil {
		return nil, fmt.Errorf("open disk: %w", err)
	}
	c := &container{f: f}

	hdr := make([]byte, 4096) // minimum APFS block size
	if _, err := f.ReadAt(hdr, 0); err != nil {
		f.Close()
		return nil, fmt.Errorf("read block 0: %w", err)
	}

	if le.Uint32(hdr[nxMagicOff:]) == nxMagic {
		// Raw APFS container (no partition table).
		c.blockSize = le.Uint32(hdr[nxBlockSizeOff:])
	} else {
		// Look for a GPT partition table and find the APFS partition.
		offset, err := findAPFSPartitionGPT(f)
		if err != nil {
			f.Close()
			return nil, fmt.Errorf("finding APFS partition: %w", err)
		}
		c.baseOffset = offset
		if _, err := f.ReadAt(hdr, offset); err != nil {
			f.Close()
			return nil, fmt.Errorf("read APFS superblock at offset %d: %w", offset, err)
		}
		if le.Uint32(hdr[nxMagicOff:]) != nxMagic {

View on GitHub (pinned to dd909d0973)

Solutions

  1. Check the image file is non-empty and at least 4096 bytes (`ls -la` / `stat`).
  2. Re-copy or re-export the disk image if it is truncated.
  3. Verify you are targeting the correct disk/device path.
  4. Test raw readability first with a small Go ReadAt or `dd if=image bs=4096 count=1` to isolate I/O problems.

Example fix

// before
apfs.Chown("empty.img", ...) // read block 0: EOF
// after
if fi, err := os.Stat("disk.img"); err == nil && fi.Size() >= 4096 {
    apfs.Chown("disk.img", ...)
}
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(diskPath)
if err != nil || fi.Size() < 4096 {
    return fmt.Errorf("image %q too small (%v bytes)", diskPath, fi.Size())
}

Try / catch

if err := apfs.Chown(diskPath, role, uid, gid, paths...); err != nil {
    if strings.Contains(err.Error(), "read block 0") {
        // truncated/unreadable image: re-copy from source
    }
    return err
}

Prevention

When it happens

Trigger: apfs.Chown called on a zero-length or truncated file (ReadAt at offset 0 on an empty file returns io.EOF), an unreadable block device, or an image on failing storage.

Common situations: Pointing Chown at an empty placeholder file; an interrupted download/copy left a truncated image; a sparse image that failed to materialize; wrong device node for the target disk.

Related errors


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