gohugoio/hugo · error
incompatible map types, got %T to %T
Error message
incompatible map types, got %T to %T
What it means
Both merge arguments are maps, but their reflect key types differ (e.g. map[string]any vs map[int]any), so Hugo cannot merge them coherently. The error prints both concrete Go types. Key comparison is on the map key type, not the element type.
Source
Thrown at tpl/collections/merge.go:65
// merge creates a copy of dst and merges src into it.
func (ns *Namespace) merge(src, dst any) (any, error) {
vdst, vsrc := reflect.ValueOf(dst), reflect.ValueOf(src)
if vdst.Kind() != reflect.Map {
return nil, fmt.Errorf("destination must be a map, got %T", dst)
}
if !hreflect.IsTruthfulValue(vsrc) {
return dst, nil
}
if vsrc.Kind() != reflect.Map {
return nil, fmt.Errorf("source must be a map, got %T", src)
}
if vsrc.Type().Key() != vdst.Type().Key() {
return nil, fmt.Errorf("incompatible map types, got %T to %T", src, dst)
}
return mergeMap(vdst, vsrc).Interface(), nil
}
func caseInsensitiveLookup(m, k reflect.Value) (reflect.Value, bool) {
if m.Type().Key().Kind() != reflect.String || k.Kind() != reflect.String {
// Fall back to direct lookup.
v := m.MapIndex(k)
return v, hreflect.IsTruthfulValue(v)
}
k2 := reflect.New(m.Type().Key()).Elem()
iter := m.MapRange()
for iter.Next() {
k2.SetIterKey(iter)
if strings.EqualFold(k.String(), k2.String()) {View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Print both types (`printf "%T / %T" $src $dst`) to identify the mismatched key type.
- Rebuild one side with string keys, e.g. reconstruct with `dict` in a loop, or quote numeric keys in the YAML/JSON source.
- Prefer `dict`-built maps and standard data files (which yield string keys) on both sides.
- Upgrade Hugo — newer versions normalize decoded maps to string keys more consistently.
Example fix
# before (data/nums.yaml) 1: one 2: two # after "1": one "2": two
Defensive patterns
Strategy: validation
Validate before calling
{{/* ensure both maps use string keys */}}{{ $dst := dict "a" 1 }}{{ $src := dict "b" 2 }}{{ $merged := merge $dst $src }} Type guard
{{ $compatible := and (reflect.IsMap $dst) (reflect.IsMap $src) }} Try / catch
{{ with try (merge $dst $src) }}{{ with .Err }}{{ errorf "incompatible map types: %s" . }}{{ end }}{{ end }} Prevention
- Build both maps with dict so key types match (string keys)
- Avoid merging maps sourced from differently-typed data files (e.g. JSON vs TOML with integer keys)
- Normalize data through jsonify/unmarshal round-trip if key types may differ
When it happens
Trigger: `merge` called with maps whose key types differ: a `map[string]interface{}` from front matter merged with a `map[interface{}]interface{}` from an older YAML decoder or a Go-constructed `map[int]...` from a data source. Constructing a dict with non-string keys via custom shortcode/partial data.
Common situations: Mixing data from JSON (string keys) with YAML sources decoded to interface keys in older Hugo/library versions; merging site config maps with maps built by `dict` (always string-keyed) against maps from external data files with numeric keys; version upgrades changing the YAML library's map key type.
Related errors
- destination must be a map, got %T
- source must be a map, got %T
- error building site: %w
- failed to create config from modules config: %w
- failed to detect format from content
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/6329c41db7f1af5e.json.
Report an issue: GitHub ↗.