lima-vm/lima · error
failed to unmarshal xml: %w
Error message
failed to unmarshal xml: %w
What it means
parseDiskutilImageAttachOutput parses the plist XML emitted by `diskutil image attach -plist -nomount`. This error wraps a failure from encoding/xml Unmarshal, meaning the output was not well-formed XML plist. diskutil's output is treated as a contract; malformed output breaks parsing.
Source
Thrown at pkg/imgutil/nativeimgutil/asifutil/asif_darwin.go:86
resizeArgs := []string{"image", "resize", "--size", fmt.Sprintf("%d", size), path}
if output, err := exec.CommandContext(context.Background(), "diskutil", resizeArgs...).CombinedOutput(); err != nil {
return fmt.Errorf("failed to resize ASIF image %#q: %w: %s", path, err, output)
}
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"]View on GitHub (pinned to dd909d0973)
Solutions
- Log the raw xmlStr alongside the wrapped error to inspect what diskutil returned
- Check the wrapped Unmarshal error for the malformed offset/element
- Verify the attach actually succeeded; handle non-plist error output before parsing
- Account for macOS-version differences in the plist schema used by the plist package
Example fix
// before
out, err := exec.Command("diskutil", "image", "attach", "--plist", "-nomount", path).Output()
// after
var stderr bytes.Buffer
cmd := exec.Command("diskutil", "image", "attach", "--plist", "-nomount", path)
cmd.Stderr = &stderr
out, err := cmd.Output()
if err != nil {
return fmt.Errorf("attach failed: %w: %s", err, stderr.String()) // avoid parsing non-plist output
} Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: check output looks like a plist before parsing
func looksLikePlist(s string) bool { return strings.HasPrefix(strings.TrimSpace(s), "<?xml") } Try / catch
disk, err := asifutil.DiskutilImageAttachNoMount(path)
if err != nil {
if strings.Contains(err.Error(), "failed to unmarshal xml") {
log.Printf("diskutil returned non-plist output; attach likely failed")
}
return err
} Prevention
- Capture stderr separately so error text never mixes into plist stdout
- Log raw diskutil output on parse failure for diagnosis
- Pin/test against the macOS versions you support
When it happens
Trigger: DiskutilImageAttachNoMount receives output that xml.Unmarshal rejects: truncated output, stderr mixed into stdout, a localized/error message instead of plist, or plist format variations encoding/xml cannot map into plist.Plist.
Common situations: Older/newer macOS emitting a different plist structure; attaching fails and diskutil prints a human-readable error instead of plist; output truncation from process signal or pipe buffering issues.
Related errors
- unexpected plist format: missing root dict
- invalid plist: top-level value is not a dict
- invalid plist: IORegistryEntryChildren not found or empty
- invalid plist: IOPlatformUUID not found in any child of IORe
- invalid date value: %w
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/512d9b8d20df5e00.
Report an issue: GitHub.