glanceapp/glance · error

orderedMap: expected mapping node, got %d

Error message

orderedMap: expected mapping node, got %d

What it means

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).

Source

Thrown at internal/glance/config.go:604

		data: make(map[K]V, len(self.data)+len(other.data)),
	}

	merged.keys = append(merged.keys, self.keys...)
	maps.Copy(merged.data, self.data)

	for _, key := range other.keys {
		if _, exists := self.data[key]; !exists {
			merged.keys = append(merged.keys, key)
		}
	}
	maps.Copy(merged.data, other.data)

	return merged
}

func (om *orderedYAMLMap[K, V]) UnmarshalYAML(node *yaml.Node) error {
	if node.Kind != yaml.MappingNode {
		return fmt.Errorf("orderedMap: expected mapping node, got %d", node.Kind)
	}

	if len(node.Content)%2 != 0 {
		return fmt.Errorf("orderedMap: expected even number of content items, got %d", len(node.Content))
	}

	om.keys = make([]K, len(node.Content)/2)
	om.data = make(map[K]V, len(node.Content)/2)

	for i := 0; i < len(node.Content); i += 2 {
		keyNode := node.Content[i]
		valueNode := node.Content[i+1]

		var key K
		if err := keyNode.Decode(&key); err != nil {
			return fmt.Errorf("orderedMap: decoding key: %v", err)
		}

View on GitHub (pinned to 91324e8de7)

Solutions

  1. Rewrite the YAML at that key as a mapping (key: value lines), not a list or scalar
  2. Compare with the docs for the specific field — if examples show named keys, use named keys
  3. If Kind is 2, you wrote a sequence; if 4, a scalar — convert to a block mapping

Example fix

# before (list where mapping expected)
groups:
  - group-a:
      widgets: []
# after (mapping)
groups:
  group-a:
    widgets: []
Defensive patterns

Strategy: type-guard

Validate before calling

// Before unmarshal, assert the node shape at the offending key:
var probe yaml.Node
_ = yaml.Unmarshal(raw, &probe)
// walk to the field and check probe.Kind == yaml.MappingNode before full decode

Type guard

func isMappingNode(n *yaml.Node) bool {
    return n != nil && n.Kind == yaml.MappingNode
}

Try / catch

if err := yaml.Unmarshal(raw, &cfg); err != nil {
    if strings.Contains(err.Error(), "orderedMap: expected mapping node") {
        // locate the non-mapping key in the YAML and rewrite it as key: value pairs
        log.Printf("config shape error: %v", err)
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15). Data as JSON: /api/errors/c5f87139747a1ba0. Report an issue: GitHub.