{"record":{"id":"8251827a9675ee82","repo":"lima-vm/lima","slug":"read-block-0-w","errorCode":null,"errorMessage":"read block 0: %w","messagePattern":"read block 0: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apfs/chown.go","lineNumber":75,"sourceCode":"\n// volumeInfo holds resolved volume information.\ntype volumeInfo struct {\n\tomapTreeAddr uint64 // physical address of volume omap B-tree root\n\trootTreeOID  uint64 // virtual OID of filesystem B-tree root\n\tlatestXID    uint64 // transaction ID of the volume superblock\n}\n\nfunc openContainer(path string) (*container, error) {\n\tf, err := os.OpenFile(path, os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"open disk: %w\", err)\n\t}\n\tc := &container{f: f}\n\n\thdr := make([]byte, 4096) // minimum APFS block size\n\tif _, err := f.ReadAt(hdr, 0); err != nil {\n\t\tf.Close()\n\t\treturn nil, fmt.Errorf(\"read block 0: %w\", err)\n\t}\n\n\tif le.Uint32(hdr[nxMagicOff:]) == nxMagic {\n\t\t// Raw APFS container (no partition table).\n\t\tc.blockSize = le.Uint32(hdr[nxBlockSizeOff:])\n\t} else {\n\t\t// Look for a GPT partition table and find the APFS partition.\n\t\toffset, err := findAPFSPartitionGPT(f)\n\t\tif err != nil {\n\t\t\tf.Close()\n\t\t\treturn nil, fmt.Errorf(\"finding APFS partition: %w\", err)\n\t\t}\n\t\tc.baseOffset = offset\n\t\tif _, err := f.ReadAt(hdr, offset); err != nil {\n\t\t\tf.Close()\n\t\t\treturn nil, fmt.Errorf(\"read APFS superblock at offset %d: %w\", offset, err)\n\t\t}\n\t\tif le.Uint32(hdr[nxMagicOff:]) != nxMagic {","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/apfs/chown.go#L57-L93","documentation":"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\".","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the image file is non-empty and at least 4096 bytes (`ls -la` / `stat`).","Re-copy or re-export the disk image if it is truncated.","Verify you are targeting the correct disk/device path.","Test raw readability first with a small Go ReadAt or `dd if=image bs=4096 count=1` to isolate I/O problems."],"exampleFix":"// before\napfs.Chown(\"empty.img\", ...) // read block 0: EOF\n// after\nif fi, err := os.Stat(\"disk.img\"); err == nil && fi.Size() >= 4096 {\n    apfs.Chown(\"disk.img\", ...)\n}","handlingStrategy":"validation","validationCode":"fi, err := os.Stat(diskPath)\nif err != nil || fi.Size() < 4096 {\n    return fmt.Errorf(\"image %q too small (%v bytes)\", diskPath, fi.Size())\n}","typeGuard":null,"tryCatchPattern":"if err := apfs.Chown(diskPath, role, uid, gid, paths...); err != nil {\n    if strings.Contains(err.Error(), \"read block 0\") {\n        // truncated/unreadable image: re-copy from source\n    }\n    return err\n}","preventionTips":["Verify image size after copy/download before processing.","Checksum images after transfer to detect truncation.","Avoid reading images directly from flaky removable media; copy to local disk first."],"tags":["apfs","io","disk-image","corruption"],"backgroundTag":"io-read-failed","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}