{"record":{"id":"319fd02c7b0bf259","repo":"gohugoio/hugo","slug":"argument-must-be-a-slice","errorCode":null,"errorMessage":"argument must be a slice","messagePattern":"argument must be a slice","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/collections.go","lineNumber":401,"sourceCode":"\n\tif limitv > seqv.Len() {\n\t\tlimitv = seqv.Len()\n\t}\n\n\treturn seqv.Slice(seqv.Len()-limitv, seqv.Len()).Interface(), nil\n}\n\n// Reverse creates a copy of the list l and reverses it.\nfunc (ns *Namespace) Reverse(l any) (any, error) {\n\tif l == nil {\n\t\treturn nil, nil\n\t}\n\tv := reflect.ValueOf(l)\n\n\tswitch v.Kind() {\n\tcase reflect.Slice:\n\tdefault:\n\t\treturn nil, errors.New(\"argument must be a slice\")\n\t}\n\n\tsliceCopy := reflect.MakeSlice(v.Type(), v.Len(), v.Len())\n\n\tfor i := v.Len() - 1; i >= 0; i-- {\n\t\telement := sliceCopy.Index(i)\n\t\telement.Set(v.Index(v.Len() - 1 - i))\n\t}\n\n\treturn sliceCopy.Interface(), nil\n}\n\n// Sanity check for slices created by Seq and D.\nconst maxSeqSize = 1000000\n\nvar errSeqSizeExceedsLimit = errors.New(\"size of result exceeds limit\")\n\n// Seq creates a sequence of integers from args. It's named and used as GNU's seq.","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/collections.go#L383-L419","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n{{ reverse .Params.tags }}\n// after\n{{ $tags := slice }}{{ range .Params.tags }}{{ $tags = $tags | append . }}{{ end }}\n{{ reverse $tags }}","handlingStrategy":"type-guard","validationCode":"{{ if reflect.IsSlice .Items }}{{ reverse .Items }}{{ end }}","typeGuard":"// In Go:\n// func isSlice(v any) bool {\n//   return v != nil && reflect.ValueOf(v).Kind() == reflect.Slice\n// }","tryCatchPattern":null,"preventionTips":["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."],"tags":["hugo","template","collections","reverse","type-mismatch","reflection"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}