{"record":{"id":"c2d81fae648090ed","repo":"glanceapp/glance","slug":"orderedmap-expected-even-number-of-content-items","errorCode":null,"errorMessage":"orderedMap: expected even number of content items, got %d","messagePattern":"orderedMap: expected even number of content items, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/config.go","lineNumber":608,"sourceCode":"\tmaps.Copy(merged.data, self.data)\n\n\tfor _, key := range other.keys {\n\t\tif _, exists := self.data[key]; !exists {\n\t\t\tmerged.keys = append(merged.keys, key)\n\t\t}\n\t}\n\tmaps.Copy(merged.data, other.data)\n\n\treturn merged\n}\n\nfunc (om *orderedYAMLMap[K, V]) UnmarshalYAML(node *yaml.Node) error {\n\tif node.Kind != yaml.MappingNode {\n\t\treturn fmt.Errorf(\"orderedMap: expected mapping node, got %d\", node.Kind)\n\t}\n\n\tif len(node.Content)%2 != 0 {\n\t\treturn fmt.Errorf(\"orderedMap: expected even number of content items, got %d\", len(node.Content))\n\t}\n\n\tom.keys = make([]K, len(node.Content)/2)\n\tom.data = make(map[K]V, len(node.Content)/2)\n\n\tfor i := 0; i < len(node.Content); i += 2 {\n\t\tkeyNode := node.Content[i]\n\t\tvalueNode := node.Content[i+1]\n\n\t\tvar key K\n\t\tif err := keyNode.Decode(&key); err != nil {\n\t\t\treturn fmt.Errorf(\"orderedMap: decoding key: %v\", err)\n\t\t}\n\n\t\tif _, ok := om.data[key]; ok {\n\t\t\treturn fmt.Errorf(\"orderedMap: duplicate key %v\", key)\n\t\t}\n","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/config.go#L590-L626","documentation":"This error is returned by the custom orderedYAMLMap unmarshaler when a YAML mapping node contains an odd number of content items. In go-yaml, a MappingNode's Content slice always alternates key/value pairs, so an odd length means the YAML document itself is structurally malformed (e.g. a key with no value). It is essentially a defensive sanity check that fires before the key/value decode loop runs.","triggerScenarios":"Unmarshalling any YAML mapping into an orderedYAMLMap field (theme presets, config maps) where the parsed node.Content has odd length. This only occurs with a corrupted YAML document or a malformed node produced by custom decoding logic, since go-yaml itself rejects odd mappings at parse time.","commonSituations":"Hand-edited glance.yml with a truncated mapping (e.g. a theme preset key with no properties), config files with unbalanced merge keys, or programmatic YAML generation that drops a value node.","solutions":["Check the config file near the mapping reported in the surrounding error for a key without a value and add the missing value or remove the key","Validate the YAML with a linter or `glance config-check`/re-parse with a strict YAML tool before running the app","If generating YAML programmatically, ensure every emitted key also emits a value node"],"exampleFix":"# before\ntheme:\n  presets:\n    my-theme:\n# after\ntheme:\n  presets:\n    my-theme:\n      color-scheme: dark\n","handlingStrategy":"validation","validationCode":"// Pre-validate config YAML structure before passing to glance\nimport \"gopkg.in/yaml.v3\"\n\nfunc mappingIsBalanced(src []byte) error {\n    var v any\n    if err := yaml.Unmarshal(src, &v); err != nil {\n        return err // syntax error surfaces here first\n    }\n    return nil\n}\n","typeGuard":null,"tryCatchPattern":"Catch the error at config load and surface file/line from the wrapped yaml error, then re-prompt the user/editor for a corrected file rather than retrying.","preventionTips":["Lint YAML in CI with yamllint before deploying","Never hand-truncate mapping blocks; delete whole key/value pairs","Use editor YAML language servers that flag structural errors on save"],"tags":["yaml","config","parsing"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}