gohugoio/hugo · error
expected a slice, got %T
Error message
expected a slice, got %T
What it means
`collections.Append` implements the template `append` function. After dereferencing the first argument, if it's non-nil but not a slice (a string, map, number, page, etc.), appending is impossible and this error names the concrete type. Only slices (or nil, which starts a new slice) are valid append targets.
Source
Thrown at common/collections/append.go:44
func Append(to any, from ...any) (any, error) {
if len(from) == 0 {
return to, nil
}
tov, toIsNil := hreflect.Indirect(reflect.ValueOf(to))
toIsNil = toIsNil || to == nil
var tot reflect.Type
if !toIsNil {
if tov.Kind() == reflect.Slice {
// Create a copy of tov, so we don't modify the original.
c := reflect.MakeSlice(tov.Type(), tov.Len(), tov.Len()+len(from))
reflect.Copy(c, tov)
tov = c
}
if tov.Kind() != reflect.Slice {
return nil, fmt.Errorf("expected a slice, got %T", to)
}
tot = tov.Type().Elem()
if tot.Kind() == reflect.Slice {
totvt := tot.Elem()
fromvs := make([]reflect.Value, len(from))
for i, f := range from {
fromv := reflect.ValueOf(f)
fromt := fromv.Type()
if fromt.Kind() == reflect.Slice {
fromt = fromt.Elem()
}
if totvt != fromt {
return nil, fmt.Errorf("cannot append slice of %s to slice of %s", fromt, totvt)
} else {
fromvs[i] = fromv
}
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Ensure the collection argument (the last one in Hugo's `append`) is a slice — initialize with `$s := slice`, not a string.
- If appending to a page param, fix the front matter so the field is a list (`items: [a]` not `items: a`).
- When accumulating in templates, start with `$acc := slice` and reassign: `$acc = $acc | append $item`.
Example fix
{{/* before */}}
{{ $s := "" }}
{{ $s = append "x" $s }}
{{/* after */}}
{{ $s := slice }}
{{ $s = append "x" $s }} Defensive patterns
Strategy: type-guard
Validate before calling
rv := reflect.ValueOf(to)
if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array {
return fmt.Errorf("append target must be a slice, got %T", to)
} Type guard
func isSlice(v any) bool {
k := reflect.TypeOf(v).Kind()
return k == reflect.Slice || k == reflect.Array
} Try / catch
{{ $s := $x }}
{{ if not (reflect.IsSlice $s) }}{{ $s = slice $s }}{{ end }}
{{ $s = $s | append $item }} Prevention
- Initialize accumulators with `slice` (e.g. `{{ $items := slice }}`) before using `append` in templates
- Never append onto a scalar or map — the first argument set must be a slice
- Use `reflect.IsSlice` in templates to guard values of uncertain shape (e.g. params that may be scalar or list)
When it happens
Trigger: Template code calling `append` with a non-slice first collection: `{{ append "a" $x }}`, `{{ append .Params.title $x }}`, or appending onto a value produced by `dict`. Note the argument order — in Hugo, `append ELEMENT COLLECTION` (collection last) also flows through this when the collection position holds a non-slice.
Common situations: Confusing Hugo's `append` argument order with Go's, so a scalar ends up in the slice position; a `.Params` field expected to be a list but authored as a string in front matter; appending to a `.Scratch` value that was set to a scalar earlier.
Related errors
- symdiff: failed to convert value: %w
- unable to convert value of type %q to %q
- 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/5fd1561695aef9d5.json.
Report an issue: GitHub ↗.