lima-vm/lima · error
expected <key> element, got <%s>
Error message
expected <key> element, got <%s>
What it means
In a plist <dict>, keys must alternate with values and keys are encoded as <key> elements. Dict.UnmarshalXML (pkg/plist/plist.go:194) requires every start element it reads inside a <dict> to be <key>; anything else (a value element at key position, nesting mistakes, missing value after a key) triggers "expected <key> element, got <%s>".
Source
Thrown at pkg/plist/plist.go:194
}
}
}
func (d *Dict) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
*d = make(map[string]Value)
for {
tok, err := dec.Token()
if err != nil {
if errors.Is(err, io.EOF) {
return nil
}
return err
}
switch t := tok.(type) {
case xml.StartElement:
if t.Name.Local != "key" {
return fmt.Errorf("expected <key> element, got <%s>", t.Name.Local)
}
var key string
if err := dec.DecodeElement(&key, &t); err != nil {
return err
}
var vs xml.StartElement
for {
vt, err := dec.Token()
if err != nil {
return err
}
if se, ok := vt.(xml.StartElement); ok {
vs = se
break
}
}
var v Value
if err := dec.DecodeElement(&v, &vs); err != nil {View on GitHub (pinned to dd909d0973)
Solutions
- Ensure every <dict> child sequence is strictly alternating <key>k</key><value/>, <key>k</key><value/> …
- Look at the %s tag in the error to find the misplaced element and add or reorder the missing <key>
- Validate the plist with plutil -lint (macOS) or xmllint against the plist DTD before parsing
- Regenerate the dict programmatically instead of hand-editing to guarantee key/value pairing
Example fix
// before (fails: value where key expected) <dict> <string>value</string> <key>k</key><string>v</string> </dict> // after <dict> <key>name</key><string>value</string> <key>k</key><string>v</string> </dict>
Defensive patterns
Strategy: validation
Validate before calling
func validateDictAlternation(data []byte) error {
dec := xml.NewDecoder(bytes.NewReader(data))
depth, expectKey := 0, false
for {
tok, err := dec.Token()
if err == io.EOF { return nil }
if err != nil { return err }
se, ok := tok.(xml.StartElement)
if !ok { continue }
switch se.Name.Local {
case "dict":
depth++; expectKey = true
case "key":
if depth > 0 && !expectKey { return errors.New("<key> without preceding pair") }
expectKey = false
default:
if depth > 0 && expectKey { return fmt.Errorf("expected <key>, got <%s>", se.Name.Local) }
expectKey = true
}
}
} Try / catch
var v plist.Value
if err := xml.Unmarshal(data, &v); err != nil {
if strings.HasPrefix(err.Error(), "expected <key> element, got <") {
tag := strings.TrimSuffix(strings.TrimPrefix(err.Error(), "expected <key> element, got <"), ">")
// locate and fix the misplaced element in the <dict>
}
return err
} Prevention
- Keep every <dict> as strict key/value alternation; add both halves together when editing
- Regenerate dicts programmatically rather than hand-editing XML
- Run plutil -lint or xmllint with the plist DTD on inputs before parsing
- Never emit two adjacent value elements or leave a <key> without its value
When it happens
Trigger: Decoding a plist whose <dict> contains a value element (e.g. <string>) where a <key> is expected — typically because a key/value pair is incomplete, two values were adjacent, or elements were mis-ordered after hand editing.
Common situations: Hand-edited plists that dropped a value after a <key>, duplicated keys' values, or placed children out of order; programmatic generators that emit value elements before keys; truncated documents.
Related errors
- unsupported plist type: %s
- failed to unmarshal xml: %w
- unexpected plist format: missing root dict
- failed to unmarshal service object: %w (line=%#q)
- invalid plist: top-level value is not a dict
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/4f7892159939356f.
Report an issue: GitHub.