gohugoio/hugo · error
expected a slice, got %T
Error message
expected a slice, got %T
What it means
Returned by collections.Append when the `to` argument is not nil and does not resolve (after dereferencing pointers/interfaces) to a reflect.Slice kind. Append's contract is 'append one slice to another'; a non-slice receiver breaks that contract. The %T verb substitutes the actual Go type of the offending value.
Solutions
- Make sure the first argument is a slice (e.g. []string, []any) or nil/nil slice.
- If the value may be a single element, wrap it: `[]any{value}` before appending.
- If loading from config/frontmatter, validate the field is a list before calling Append.
- For arrays, convert to a slice first via `s[:]`.
Example fix
// before
collections.Append("hello", "world")
// after
collections.Append([]string{"hello"}, "world") Defensive patterns
Strategy: type-guard
Validate before calling
func isSlice(v any) bool {
if v == nil { return true }
rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
if rv.IsNil() { return true }
rv = rv.Elem()
}
return rv.Kind() == reflect.Slice
} Type guard
func isAppendableSlice(v any) bool { return isSlice(v) } Prevention
- Wrap collections.Append calls in a helper that asserts the first arg is a slice.
- When loading from config, coerce frontmatter lists with cast before appending.
- Never pass structs/maps as the head argument.
When it happens
Trigger: Calling collections.Append(to, from...) where `to` is a struct, map, scalar, array ([N]T not []T), or a pointer to a non-slice. Pass nil to `to` is allowed; passing a concrete non-slice value is not.
Common situations: Template authors calling `append` (Hugo's `collections.Append` exposed as `append`) with the head argument bound to `.Params.someScalar` or a map instead of a slice. Programmatic callers passing `&myStruct` by mistake instead of `&mySlice`.
Related errors
- cannot append slice of
- argument must be a slice
- can't apply over
- can't iterate over %T
- can't slice item of type
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/5fd1561695aef9d5.
Report an issue: GitHub.
Appendix: 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 52c9bd7908)