{"record":{"id":"d77eb3c4323bd59d","repo":"lima-vm/lima","slug":"unexpected-plist-format-missing-root-dict","errorCode":null,"errorMessage":"unexpected plist format: missing root dict","messagePattern":"unexpected plist format: missing root dict","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/imgutil/nativeimgutil/asifutil/asif_darwin.go","lineNumber":90,"sourceCode":"\treturn nil\n}\n\ntype AttachedDisk struct {\n\tDisk      string // whole disk device, e.g. \"disk4\" (GUID_partition_scheme)\n\tContainer string // APFS container partition, e.g. \"disk4s2\" (Apple_APFS)\n\tData      string // data volume device, e.g. \"disk7s5\"\n}\n\n// parseDiskutilImageAttachOutput parses the output of `diskutil image attach -plist -nomount <disk>`\n// and returns the attached disk information.\nfunc parseDiskutilImageAttachOutput(xmlStr string) (*AttachedDisk, error) {\n\tvar p plist.Plist\n\tif err := xml.Unmarshal([]byte(xmlStr), &p); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal xml: %w\", err)\n\t}\n\n\tif p.Value.Dict == nil {\n\t\treturn nil, errors.New(\"unexpected plist format: missing root dict\")\n\t}\n\n\tseVal, ok := p.Value.Dict[\"system-entities\"]\n\tif !ok || len(seVal.Array) == 0 {\n\t\treturn nil, errors.New(\"unexpected plist format: missing system-entities array\")\n\t}\n\n\tresult := &AttachedDisk{}\n\tfor _, devEnt := range seVal.Array {\n\t\tdevDict := devEnt.Dict\n\t\tif devDict == nil {\n\t\t\tcontinue\n\t\t}\n\t\tdevEntry, hasDevEntry := devDict[\"dev-entry\"]\n\t\tif !hasDevEntry || devEntry.String == nil || *devEntry.String == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif hint, ok := devDict[\"content-hint\"]; ok && hint.String != nil {","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/imgutil/nativeimgutil/asifutil/asif_darwin.go#L72-L108","documentation":"parseDiskutilImageAttachOutput validates that the parsed plist has the expected structure: a root dictionary containing a `system-entities` array of disk entities. This error means the XML parsed fine but the root dict is missing, so diskutil returned an unexpected plist shape. It guards against indexing into an absent structure.","triggerScenarios":"DiskutilImageAttachNoMount gets a plist whose root is an array (not a dict) or otherwise lacks a top-level dict — e.g. a different plist schema on another macOS version, or an error plist from diskutil.","commonSituations":"macOS version changed the `diskutil image attach -plist` schema; diskutil returned a plist describing something else than attached image entities; middleware/logging wrappers altered the output shape.","solutions":["Dump the plist output and compare its root type (dict vs array) against expectations","Update the parser/plist mapping for the current macOS schema","Check macOS version compatibility; adapt parsing per version if needed","Treat the attach as failed and surface the raw output for diagnosis"],"exampleFix":"// before\nif p.Value.Dict == nil {\n    return nil, errors.New(\"unexpected plist format: missing root dict\")\n}\n// after (tolerate array-root plists)\nif p.Value.Dict == nil && len(p.Value.Array) == 0 {\n    return nil, fmt.Errorf(\"unexpected plist format: root is neither dict nor array: %T\", p.Value)\n}","handlingStrategy":"type-guard","validationCode":"// preflight: structural check after unmarshal is inherent; validate expected keys before use\nif p.Value == nil || p.Value.Dict == nil { return errors.New(\"plist root is not a dict\") }","typeGuard":"func hasRootDict(p *plist.Plist) bool { return p != nil && p.Value != nil && p.Value.Dict != nil }","tryCatchPattern":"disk, err := asifutil.DiskutilImageAttachNoMount(path)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected plist format\") {\n        log.Printf(\"diskutil plist schema differs on this macOS; inspect raw output\")\n    }\n    return err\n}","preventionTips":["Test the parser against plists from all supported macOS versions","Check the root plist type (dict vs array) before accessing keys","Surface the raw plist in errors so schema drift is diagnosable"],"tags":["macos","plist","schema","parsing"],"backgroundTag":"plist-schema-mismatch","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}