gohugoio/hugo · error

union does not support slices or arrays of uncomparable type

Error message

union does not support slices or arrays of uncomparable types

What it means

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

Source

Thrown at tpl/collections/collections.go:672

		case reflect.Array, reflect.Slice:
			ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[any]bool)}

			if l1v.Type() != l2v.Type() &&
				l1v.Type().Elem().Kind() != reflect.Interface &&
				l2v.Type().Elem().Kind() != reflect.Interface {
				return ins.r.Interface(), nil
			}

			var (
				l1vv  reflect.Value
				isNil bool
			)

			for i := range l1v.Len() {
				l1vv, isNil = hreflect.Indirect(l1v.Index(i))

				if !l1vv.Type().Comparable() {
					return []any{}, errors.New("union does not support slices or arrays of uncomparable types")
				}

				if !isNil {
					ins.appendIfNotSeen(l1vv)
				}
			}

			if !l1vv.IsValid() {
				// The first slice may be empty. Pick the first value of the second
				// to use as a prototype.
				if l2v.Len() > 0 {
					l1vv = l2v.Index(0)
				}
			}

			for j := range l2v.Len() {
				l2vv := l2v.Index(j)
				typ := l1vv.Type()

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Union only slices of comparable elements (strings, numbers, pages/pointers).
  2. 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.
  3. Alternatively concatenate with `append` and dedupe with `uniq` on a comparable projection.

Example fix

<!-- before -->
{{ $all := union $listOfDicts1 $listOfDicts2 }}
<!-- after: union comparable keys instead -->
{{ $keys := union (apply $listOfDicts1 "index" "." "id") (apply $listOfDicts2 "index" "." "id") }}
Defensive patterns

Strategy: type-guard

Validate before calling

{{/* union requires comparable element types — scalars, not maps/slices */}}
{{ $ok := true }}
{{ range $a }}{{ if or (reflect.IsMap .) (reflect.IsSlice .) }}{{ $ok = false }}{{ end }}{{ end }}
{{ if $ok }}{{ $u := union $a $b }}{{ end }}

Type guard

{{ $comparable := not (or (reflect.IsMap (index $a 0)) (reflect.IsSlice (index $a 0))) }}

Prevention

When it happens

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

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

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/c8aff4eb1418b4f0.json. Report an issue: GitHub ↗.