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

  1. Ensure the input is a slice: build a slice from map values first (e.g. via sort or a scratch-built slice) before reversing.
  2. Replace {{ reverse "abc" }} with string handling if you actually wanted to reverse a string.
  3. 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

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


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)