gohugoio/hugo · error
argument must be a slice
Error message
argument must be a slice
What it means
Thrown by the Reverse template function when the argument's reflected Kind is not reflect.Slice (line 401). Reverse intentionally accepts only slices (not arrays, not strings); anything else is rejected. Note arrays are NOT accepted here even though other collection functions accept them.
Solutions
- Ensure the input is a slice: build a slice from map values first (e.g. via sort or a scratch-built slice) before reversing.
- Replace {{ reverse "abc" }} with string handling if you actually wanted to reverse a string.
- Check the upstream pipeline: reverse expects the output of .Pages, slice, or a []T from a partial.
Example fix
// before
{{ reverse .Params.tags }}
// after
{{ $tags := slice }}{{ range .Params.tags }}{{ $tags = $tags | append . }}{{ end }}
{{ reverse $tags }} Defensive patterns
Strategy: type-guard
Validate before calling
{{ if reflect.IsSlice .Items }}{{ reverse .Items }}{{ end }} Type guard
// In Go:
// func isSlice(v any) bool {
// return v != nil && reflect.ValueOf(v).Kind() == reflect.Slice
// } Prevention
- Reverse accepts ONLY slices — not arrays, not strings, not maps.
- Convert map values to a slice before reversing.
- Do not pipe dict output (a map) into reverse.
When it happens
Trigger: Calling {{ reverse .Params }} (a map); {{ reverse "abc" }} (a string); passing an array by value; passing a single struct or scalar. Most commonly passing a map when a slice was expected.
Common situations: Treating a Hugo map (Params, taxonomy map) as an ordered slice; refactoring that swaps a slice field for a map; passing the result of dict (which is a map) into reverse.
Related errors
- can't apply over
- can't iterate over %T
- elements must be comparable
- incompatible map types, got %T to %T
- is not assignable to
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/319fd02c7b0bf259.
Report an issue: GitHub.
Appendix: source
Thrown at tpl/collections/collections.go:401
if limitv > seqv.Len() {
limitv = seqv.Len()
}
return seqv.Slice(seqv.Len()-limitv, seqv.Len()).Interface(), nil
}
// Reverse creates a copy of the list l and reverses it.
func (ns *Namespace) Reverse(l any) (any, error) {
if l == nil {
return nil, nil
}
v := reflect.ValueOf(l)
switch v.Kind() {
case reflect.Slice:
default:
return nil, errors.New("argument must be a slice")
}
sliceCopy := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
for i := v.Len() - 1; i >= 0; i-- {
element := sliceCopy.Index(i)
element.Set(v.Index(v.Len() - 1 - i))
}
return sliceCopy.Interface(), nil
}
// Sanity check for slices created by Seq and D.
const maxSeqSize = 1000000
var errSeqSizeExceedsLimit = errors.New("size of result exceeds limit")
// Seq creates a sequence of integers from args. It's named and used as GNU's seq.View on GitHub (pinned to 52c9bd7908)