lima-vm/lima · error

unexpected plist format: missing root dict

Error message

unexpected plist format: missing root dict

What it means

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.

Source

Thrown at pkg/imgutil/nativeimgutil/asifutil/asif_darwin.go:90

	return nil
}

type AttachedDisk struct {
	Disk      string // whole disk device, e.g. "disk4" (GUID_partition_scheme)
	Container string // APFS container partition, e.g. "disk4s2" (Apple_APFS)
	Data      string // data volume device, e.g. "disk7s5"
}

// parseDiskutilImageAttachOutput parses the output of `diskutil image attach -plist -nomount <disk>`
// and returns the attached disk information.
func parseDiskutilImageAttachOutput(xmlStr string) (*AttachedDisk, error) {
	var p plist.Plist
	if err := xml.Unmarshal([]byte(xmlStr), &p); err != nil {
		return nil, fmt.Errorf("failed to unmarshal xml: %w", err)
	}

	if p.Value.Dict == nil {
		return nil, errors.New("unexpected plist format: missing root dict")
	}

	seVal, ok := p.Value.Dict["system-entities"]
	if !ok || len(seVal.Array) == 0 {
		return nil, errors.New("unexpected plist format: missing system-entities array")
	}

	result := &AttachedDisk{}
	for _, devEnt := range seVal.Array {
		devDict := devEnt.Dict
		if devDict == nil {
			continue
		}
		devEntry, hasDevEntry := devDict["dev-entry"]
		if !hasDevEntry || devEntry.String == nil || *devEntry.String == "" {
			continue
		}
		if hint, ok := devDict["content-hint"]; ok && hint.String != nil {

View on GitHub (pinned to dd909d0973)

Solutions

  1. Dump the plist output and compare its root type (dict vs array) against expectations
  2. Update the parser/plist mapping for the current macOS schema
  3. Check macOS version compatibility; adapt parsing per version if needed
  4. Treat the attach as failed and surface the raw output for diagnosis

Example fix

// before
if p.Value.Dict == nil {
    return nil, errors.New("unexpected plist format: missing root dict")
}
// after (tolerate array-root plists)
if p.Value.Dict == nil && len(p.Value.Array) == 0 {
    return nil, fmt.Errorf("unexpected plist format: root is neither dict nor array: %T", p.Value)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// preflight: structural check after unmarshal is inherent; validate expected keys before use
if p.Value == nil || p.Value.Dict == nil { return errors.New("plist root is not a dict") }

Type guard

func hasRootDict(p *plist.Plist) bool { return p != nil && p.Value != nil && p.Value.Dict != nil }

Try / catch

disk, err := asifutil.DiskutilImageAttachNoMount(path)
if err != nil {
    if strings.Contains(err.Error(), "unexpected plist format") {
        log.Printf("diskutil plist schema differs on this macOS; inspect raw output")
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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