{"record":{"id":"6329c41db7f1af5e","repo":"gohugoio/hugo","slug":"incompatible-map-types-got-t-to-t","errorCode":null,"errorMessage":"incompatible map types, got %T to %T","messagePattern":"incompatible map types, got %T to %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/merge.go","lineNumber":65,"sourceCode":"\n// merge creates a copy of dst and merges src into it.\nfunc (ns *Namespace) merge(src, dst any) (any, error) {\n\tvdst, vsrc := reflect.ValueOf(dst), reflect.ValueOf(src)\n\n\tif vdst.Kind() != reflect.Map {\n\t\treturn nil, fmt.Errorf(\"destination must be a map, got %T\", dst)\n\t}\n\n\tif !hreflect.IsTruthfulValue(vsrc) {\n\t\treturn dst, nil\n\t}\n\n\tif vsrc.Kind() != reflect.Map {\n\t\treturn nil, fmt.Errorf(\"source must be a map, got %T\", src)\n\t}\n\n\tif vsrc.Type().Key() != vdst.Type().Key() {\n\t\treturn nil, fmt.Errorf(\"incompatible map types, got %T to %T\", src, dst)\n\t}\n\n\treturn mergeMap(vdst, vsrc).Interface(), nil\n}\n\nfunc caseInsensitiveLookup(m, k reflect.Value) (reflect.Value, bool) {\n\tif m.Type().Key().Kind() != reflect.String || k.Kind() != reflect.String {\n\t\t// Fall back to direct lookup.\n\t\tv := m.MapIndex(k)\n\t\treturn v, hreflect.IsTruthfulValue(v)\n\t}\n\n\tk2 := reflect.New(m.Type().Key()).Elem()\n\n\titer := m.MapRange()\n\tfor iter.Next() {\n\t\tk2.SetIterKey(iter)\n\t\tif strings.EqualFold(k.String(), k2.String()) {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/merge.go#L47-L83","documentation":"Thrown by Namespace.merge when the source map's key type does not equal the destination map's key type (checked via reflect Type().Key() equality). Merge requires homogeneous key types so SetMapIndex is valid; e.g. merging map[int]V into map[string]V is rejected. Both source (%T) and destination (%T) types are named.","triggerScenarios":"Calling `{{ merge $intKeyedMap $stringKeyedMap }}`, or mixing a `dict` (map[string]any) with a map[int]any built elsewhere. The vsrc.Type().Key() != vdst.Type().Key() check fires.","commonSituations":"Combining maps constructed in different places (one from JSON with string keys, one built in Go with int keys), or merging Hugo Params (string-keyed) with a custom int-keyed lookup. Common during integration of data from multiple sources.","solutions":["Normalize key types before merging — convert one map's keys to match the other.","Use `dict` consistently so all maps are map[string]any.","Merge maps of the same declared type end-to-end.","If types genuinely differ, merge manually in a loop with explicit key conversion."],"exampleFix":"// before\n{{ merge $intKeyedMap $stringKeyedMap }}\n// after\n{{ merge (dict \"a\" 1) $stringKeyedMap }}","handlingStrategy":"validation","validationCode":"func mergeKeyTypesMatch(src, dst any) error {\n    vs, vd := reflect.ValueOf(src), reflect.ValueOf(dst)\n    if vs.Kind() != reflect.Map || vd.Kind() != reflect.Map {\n        return errors.New(\"both must be maps\")\n    }\n    if vs.Type().Key() != vd.Type().Key() {\n        return fmt.Errorf(\"key types differ: %s vs %s\", vs.Type().Key(), vd.Type().Key())\n    }\n    return nil\n}","typeGuard":"func sameMapKeyType(a, b any) bool {\n    va, vb := reflect.ValueOf(a), reflect.ValueOf(b)\n    if va.Kind() != reflect.Map || vb.Kind() != reflect.Map { return false }\n    return va.Type().Key() == vb.Type().Key()\n}","tryCatchPattern":null,"preventionTips":["Use map[string]any (dict) consistently so key types align.","Normalize key types before merging maps from different sources.","Avoid mixing int-keyed and string-keyed maps in the same Merge.","Merge manually with explicit conversion if types genuinely differ."],"tags":["go","hugo","template","collections","merge","type-mismatch"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}