gohugoio/hugo · error

symdiff: failed to convert value: %w

Error message

symdiff: failed to convert value: %w

What it means

`collections.SymDiff` builds its result slice with the element type of the first slice argument, and converts each kept element to that type via `convertValue` (tpl/collections/symdiff.go:55-58). This error wraps a conversion failure: an element from the second collection cannot be represented as the first collection's element type, so a coherent result slice cannot be constructed.

Source

Thrown at tpl/collections/symdiff.go:57

		v := reflect.ValueOf(s)

		switch v.Kind() {
		case reflect.Array, reflect.Slice:
			if i == 0 {
				sliceType := v.Type()
				sliceElemType = sliceType.Elem()
				slice = reflect.MakeSlice(sliceType, 0, 0)
			}

			for i := range v.Len() {
				ev, _ := hreflect.Indirect(v.Index(i))
				key := normalize(ev)

				// Append if the key is not in their intersection.
				if ids1[key] != ids2[key] {
					v, err := convertValue(ev, sliceElemType)
					if err != nil {
						return nil, fmt.Errorf("symdiff: failed to convert value: %w", err)
					}
					slice = reflect.Append(slice, v)
				}
			}
		default:
			return nil, fmt.Errorf("arguments to symdiff must be slices or arrays")
		}
	}

	return slice.Interface(), nil
}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Make both collections the same element type before diffing — e.g. map both to strings or both to pages.
  2. When comparing pages, diff the page collections directly (`.Pages | symdiff $other.Pages`) rather than mixing pages with scalars.
  3. For mixed data, normalize with `apply` or a range that builds uniform slices, then symdiff those.

Example fix

<!-- before: pages vs strings -->
{{ $d := slice "a" "b" | symdiff .Pages }}
<!-- after: compare like with like -->
{{ $titles := slice }}{{ range .Pages }}{{ $titles = $titles | append .Title }}{{ end }}
{{ $d := slice "a" "b" | symdiff $titles }}
Defensive patterns

Strategy: validation

Validate before calling

{{/* ensure element types are comparable/convertible across the slices */}}
{{ $a := slice 1 2 3 }}
{{ $b := slice 2 3 4 }}
{{ $diff := collections.SymDiff $a $b }}

Try / catch

{{ with try (collections.SymDiff $a $b) }}
  {{ with .Err }}{{ errorf "symdiff: %s" . }}{{ else }}{{ .Value }}{{ end }}
{{ end }}

Prevention

When it happens

Trigger: Calling `{{ $a | symdiff $b }}` where the two slices have incompatible element types — e.g. a `[]int` diffed against a slice of pages or structs, or mixed-type `[]any` slices whose leftover elements can't convert to the result's concrete element type.

Common situations: Diffing `.Pages` against a hand-built `slice` of strings or params; mixing values from `.Params` (which decode as varying concrete types) with typed collections; assuming symdiff works on heterogeneous data like union types.

Related errors


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