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

  1. Log the raw xmlStr alongside the wrapped error to inspect what diskutil returned
  2. Check the wrapped Unmarshal error for the malformed offset/element
  3. Verify the attach actually succeeded; handle non-plist error output before parsing
  4. 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

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


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