{"id":"22dd48111ac3f851","repo":"gohugoio/hugo","slug":"can-t-iterate-over-a-nil-value","errorCode":null,"errorMessage":"can't iterate over a nil value","messagePattern":"can't iterate over a nil value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/sort.go","lineNumber":38,"sourceCode":"\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/gohugoio/hugo/common/hmaps\"\n\t\"github.com/gohugoio/hugo/common/hreflect\"\n\t\"github.com/gohugoio/hugo/langs\"\n\t\"github.com/gohugoio/hugo/tpl/compare\"\n\t\"github.com/spf13/cast\"\n)\n\n// Sort returns a sorted copy of the list l.\nfunc (ns *Namespace) Sort(ctx context.Context, l any, args ...any) (any, error) {\n\tif l == nil {\n\t\treturn nil, errors.New(\"sequence must be provided\")\n\t}\n\n\tseqv, isNil := hreflect.Indirect(reflect.ValueOf(l))\n\tif isNil {\n\t\treturn nil, errors.New(\"can't iterate over a nil value\")\n\t}\n\n\tctxv := reflect.ValueOf(ctx)\n\n\tvar sliceType reflect.Type\n\tswitch seqv.Kind() {\n\tcase reflect.Array, reflect.Slice:\n\t\tsliceType = seqv.Type()\n\tcase reflect.Map:\n\t\tsliceType = reflect.SliceOf(seqv.Type().Elem())\n\tdefault:\n\t\treturn nil, errors.New(\"can't sort \" + reflect.ValueOf(l).Type().String())\n\t}\n\n\tcollator := langs.GetCollator1(ns.deps.Conf.Language().(*langs.Language))\n\n\t// Create a list of pairs that will be used to do the sort\n\tp := pairList{Collator: collator, sortComp: ns.sortComp, SortAsc: true, SliceType: sliceType}","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/collections/sort.go#L20-L56","documentation":"After the literal-nil check, collections.Sort dereferences the value with hreflect.Indirect; if the argument is a typed nil (e.g. a nil pointer, nil map, or nil slice behind an interface), Indirect reports isNil and this error is returned. It distinguishes 'you passed nothing' (error 172) from 'you passed a typed value that is nil under the hood'.","triggerScenarios":"Passing a nil pointer or nil-valued typed variable to `sort` — e.g. `{{ sort $p }}` where `$p` is a nil `*Page` or a nil map returned from a partial/function, or sorting a dereferenced pointer field that was never initialized.","commonSituations":"Sorting the result of `.GetPage` when the page doesn't exist (returns nil pointer); sorting data from `getJSON`/`resources` calls that failed and returned typed nil; passing scratch/store values that were set to a typed nil earlier in the template.","solutions":["Wrap in `with` so nil values are skipped: `{{ with $seq }}{{ sort . }}{{ end }}`.","Check the producing call — e.g. verify `.Site.GetPage \"...\"` actually finds a page before sorting anything derived from it.","Initialize the collection (e.g. `slice` or `dict`) before conditionally appending, so it is never a typed nil."],"exampleFix":"<!-- before -->\n{{ $p := .Site.GetPage \"/missing\" }}\n{{ sort $p.Pages }}\n<!-- after -->\n{{ with .Site.GetPage \"/missing\" }}{{ sort .Pages }}{{ end }}","handlingStrategy":"validation","validationCode":"{{ $items := site.Data.products }}\n{{ with $items }}{{ range sort . \"name\" }}...{{ end }}{{ end }}","typeGuard":"{{ if ne $items nil }}{{ sort $items }}{{ end }}","tryCatchPattern":"{{ with try (sort site.Data.maybe) }}{{ if .Err }}{{ warnf \"nothing to sort: %s\" .Err }}{{ end }}{{ end }}","preventionTips":["Missing data files and unset params yield nil — use `with` to skip the whole block","Use `default slice` to substitute an empty slice: `sort (.Params.tags | default slice)`","Check `isset` for map keys before sorting their values"],"tags":["hugo","templates","collections","sort","nil","reflection"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}