{"id":"c8aff4eb1418b4f0","repo":"gohugoio/hugo","slug":"union-does-not-support-slices-or-arrays-of-uncompa","errorCode":null,"errorMessage":"union does not support slices or arrays of uncomparable types","messagePattern":"union does not support slices or arrays of uncomparable types","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/collections.go","lineNumber":672,"sourceCode":"\t\tcase reflect.Array, reflect.Slice:\n\t\t\tins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[any]bool)}\n\n\t\t\tif l1v.Type() != l2v.Type() &&\n\t\t\t\tl1v.Type().Elem().Kind() != reflect.Interface &&\n\t\t\t\tl2v.Type().Elem().Kind() != reflect.Interface {\n\t\t\t\treturn ins.r.Interface(), nil\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tl1vv  reflect.Value\n\t\t\t\tisNil bool\n\t\t\t)\n\n\t\t\tfor i := range l1v.Len() {\n\t\t\t\tl1vv, isNil = hreflect.Indirect(l1v.Index(i))\n\n\t\t\t\tif !l1vv.Type().Comparable() {\n\t\t\t\t\treturn []any{}, errors.New(\"union does not support slices or arrays of uncomparable types\")\n\t\t\t\t}\n\n\t\t\t\tif !isNil {\n\t\t\t\t\tins.appendIfNotSeen(l1vv)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !l1vv.IsValid() {\n\t\t\t\t// The first slice may be empty. Pick the first value of the second\n\t\t\t\t// to use as a prototype.\n\t\t\t\tif l2v.Len() > 0 {\n\t\t\t\t\tl1vv = l2v.Index(0)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor j := range l2v.Len() {\n\t\t\t\tl2vv := l2v.Index(j)\n\t\t\t\ttyp := l1vv.Type()","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/collections/collections.go#L654-L690","documentation":"`union` deduplicates elements using them as map keys, which requires every element to be comparable per Go's rules. If an element in the first slice has an uncomparable type (slice, map, or func — including such values inside `[]any`), Hugo returns this error instead of panicking on the map insert.","triggerScenarios":"`{{ union $a $b }}` where `$a` contains nested slices or maps, e.g. `union (slice (slice 1 2)) (slice (slice 3))` or unioning lists of dicts built with `dict`.","commonSituations":"Unioning lists of front-matter maps (each entry is a `map[string]any`); merging nested data-file structures; combining `slice`-of-`slice` groupings from `group` or `where` results.","solutions":["Union only slices of comparable elements (strings, numbers, pages/pointers).","For lists of maps, extract a comparable key first (e.g. `apply` to pull out an id/name), union those, then look entries back up.","Alternatively concatenate with `append` and dedupe with `uniq` on a comparable projection."],"exampleFix":"<!-- before -->\n{{ $all := union $listOfDicts1 $listOfDicts2 }}\n<!-- after: union comparable keys instead -->\n{{ $keys := union (apply $listOfDicts1 \"index\" \".\" \"id\") (apply $listOfDicts2 \"index\" \".\" \"id\") }}","handlingStrategy":"type-guard","validationCode":"{{/* union requires comparable element types — scalars, not maps/slices */}}\n{{ $ok := true }}\n{{ range $a }}{{ if or (reflect.IsMap .) (reflect.IsSlice .) }}{{ $ok = false }}{{ end }}{{ end }}\n{{ if $ok }}{{ $u := union $a $b }}{{ end }}","typeGuard":"{{ $comparable := not (or (reflect.IsMap (index $a 0)) (reflect.IsSlice (index $a 0))) }}","tryCatchPattern":null,"preventionTips":["Use union only on slices of comparable values (strings, numbers) or Pages — not slices of maps/slices.","For page collections, union works because Pages compare by identity; prefer it over hand-built dict lists.","When merging lists of dicts, key them by a unique scalar field and union the keys instead."],"tags":["hugo","templates","union","comparability","type-mismatch"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}