gohugoio/hugo · error
unable to convert value of type %q to %q
Error message
unable to convert value of type %q to %q
What it means
When Hugo's collection functions (append, union, intersect, sort comparisons, etc.) mix element types, `convertValue`/`convertNumber` try to coerce a value to the target slice's element type via reflection. If the numeric conversion is not possible (e.g. the value would not fit or the kinds are incompatible per `hreflect.ConvertIfPossible`), Hugo reports the source and destination types in this error.
Source
Thrown at tpl/collections/reflect_helpers.go:100
func convertValue(v reflect.Value, to reflect.Type) (reflect.Value, error) {
if v.Type().AssignableTo(to) {
return v, nil
}
switch kind := to.Kind(); {
case kind == reflect.String:
return hreflect.ToStringValueE(v)
case hreflect.IsNumber(kind):
return convertNumber(v, to)
default:
return reflect.Value{}, fmt.Errorf("%s is not assignable to %s", v.Type(), to)
}
}
func convertNumber(v reflect.Value, typ reflect.Type) (reflect.Value, error) {
if v, ok := hreflect.ConvertIfPossible(v, typ); ok {
return v, nil
}
return reflect.Value{}, fmt.Errorf("unable to convert value of type %q to %q", v.Type().String(), typ.String())
}
func newSliceElement(items any) any {
tp := reflect.TypeOf(items)
if tp == nil {
return nil
}
switch tp.Kind() {
case reflect.Array, reflect.Slice:
tp = tp.Elem()
if tp.Kind() == reflect.Pointer {
tp = tp.Elem()
}
return reflect.New(tp).Interface()
}
return nil
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Normalize types before combining: cast values explicitly with `int`, `float`, or `string` so both operands share a type, e.g. `{{ $s = $s | append (int $v) }}`.
- Build the slice from scratch with `slice` using consistently typed values instead of appending mixed types into an existing typed slice.
- If the data comes from JSON/YAML, remember numbers may be float64 — cast at the point of use.
Example fix
<!-- before -->
{{ $nums := site.Params.counts }}{{ $nums = $nums | append "7" }}
<!-- after -->
{{ $nums := site.Params.counts }}{{ $nums = $nums | append (int "7") }} Defensive patterns
Strategy: type-guard
Validate before calling
{{ $a := slice 1 2 }}
{{ $b := slice "3" "4" }}
{{ if eq (printf "%T" (index $a 0)) (printf "%T" (index $b 0)) }}{{ union $a $b }}{{ end }} Type guard
{{ $sameType := eq (printf "%T" $x) (printf "%T" $y) }} Try / catch
{{ with try (intersect $a $b) }}{{ with .Err }}{{ warnf "type mismatch in collection op: %s" . }}{{ else }}{{ .Value }}{{ end }}{{ end }} Prevention
- Keep both collections element-type-homogeneous before intersect/union/etc. — mixed int/string slices fail conversion
- Normalize types explicitly (e.g. `apply` with `string` or `int`) before combining collections from different sources
- Front matter can yield surprising types (int vs float vs string); cast params before set operations
When it happens
Trigger: Appending or set-combining values into a typed slice whose element type the value cannot convert to — e.g. appending a negative int or a float into a `[]uint`, or mixing incompatible numeric types where lossless conversion fails.
Common situations: Mixing data-file values (JSON numbers decode as float64) with typed slices built in templates or from Go-side params; appending template-computed ints into slices originating from config with a narrower/unsigned type; version changes that tightened type handling in collections functions.
Related errors
- symdiff: failed to convert value: %w
- expected a slice, got %T
- arguments to symdiff must be slices or arrays
- errWrongArgStructure
- errKeyIsEmptyString
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/3430df68f9e56671.json.
Report an issue: GitHub ↗.