{"record":{"id":"c5f87139747a1ba0","repo":"glanceapp/glance","slug":"orderedmap-expected-mapping-node-got-d","errorCode":null,"errorMessage":"orderedMap: expected mapping node, got %d","messagePattern":"orderedMap: expected mapping node, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/config.go","lineNumber":604,"sourceCode":"\t\tdata: make(map[K]V, len(self.data)+len(other.data)),\n\t}\n\n\tmerged.keys = append(merged.keys, self.keys...)\n\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","sourceCodeStart":586,"sourceCodeEnd":622,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/config.go#L586-L622","documentation":"orderedYAMLMap's custom UnmarshalYAML rejects any YAML node that is not a mapping. The type preserves key order for structures like widget maps where order matters; feeding it a scalar, sequence, or document node fails with the node's Kind number (0=document, 2=sequence, 4=scalar, 8=alias per go-yaml).","triggerScenarios":"Using an ordered-map-backed config field (e.g. a widget's keyed settings) but writing it as a YAML list or a plain string instead of key: value pairs. E.g. 'groups:' followed by '- name: x' where a map is expected.","commonSituations":"Confusing list syntax (- item) with mapping syntax for fields documented as maps; pasting example YAML of the wrong shape; putting a quoted string where a block mapping is required.","solutions":["Rewrite the YAML at that key as a mapping (key: value lines), not a list or scalar","Compare with the docs for the specific field — if examples show named keys, use named keys","If Kind is 2, you wrote a sequence; if 4, a scalar — convert to a block mapping"],"exampleFix":"# before (list where mapping expected)\ngroups:\n  - group-a:\n      widgets: []\n# after (mapping)\ngroups:\n  group-a:\n    widgets: []","handlingStrategy":"type-guard","validationCode":"// Before unmarshal, assert the node shape at the offending key:\nvar probe yaml.Node\n_ = yaml.Unmarshal(raw, &probe)\n// walk to the field and check probe.Kind == yaml.MappingNode before full decode","typeGuard":"func isMappingNode(n *yaml.Node) bool {\n    return n != nil && n.Kind == yaml.MappingNode\n}","tryCatchPattern":"if err := yaml.Unmarshal(raw, &cfg); err != nil {\n    if strings.Contains(err.Error(), \"orderedMap: expected mapping node\") {\n        // locate the non-mapping key in the YAML and rewrite it as key: value pairs\n        log.Printf(\"config shape error: %v\", err)\n    }\n}","preventionTips":["Match the documented YAML shape exactly for map-typed fields (no '- ' list syntax)","Use an editor with a YAML schema to catch shape mismatches live"],"tags":["glance","yaml","unmarshal","configuration"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}