{"record":{"id":"c53548f3ec78aa25","repo":"gohugoio/hugo","slug":"slice-of-nil-pointer","errorCode":null,"errorMessage":"slice of nil pointer","messagePattern":"slice of nil pointer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/funcs.go","lineNumber":249,"sourceCode":"\t\t}\n\t}\n\treturn item, nil\n}\n\n// Slicing.\n\n// slice returns the result of slicing its first argument by the remaining\n// arguments. Thus \"slice x 1 2\" is, in Go syntax, x[1:2], while \"slice x\"\n// is x[:], \"slice x 1\" is x[1:], and \"slice x 1 2 3\" is x[1:2:3]. The first\n// argument must be a string, slice, or array.\nfunc slice(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {\n\titem = indirectInterface(item)\n\tif !item.IsValid() {\n\t\treturn reflect.Value{}, fmt.Errorf(\"slice of untyped nil\")\n\t}\n\tvar isNil bool\n\tif item, isNil = indirect(item); isNil {\n\t\treturn reflect.Value{}, fmt.Errorf(\"slice of nil pointer\")\n\t}\n\tif len(indexes) > 3 {\n\t\treturn reflect.Value{}, fmt.Errorf(\"too many slice indexes: %d\", len(indexes))\n\t}\n\tvar cap int\n\tswitch item.Kind() {\n\tcase reflect.String:\n\t\tif len(indexes) == 3 {\n\t\t\treturn reflect.Value{}, fmt.Errorf(\"cannot 3-index slice a string\")\n\t\t}\n\t\tcap = item.Len()\n\tcase reflect.Array, reflect.Slice:\n\t\tcap = item.Cap()\n\tdefault:\n\t\treturn reflect.Value{}, fmt.Errorf(\"can't slice item of type %s\", item.Type())\n\t}\n\t// set default values for cases item[:], item[i:].\n\tidx := [3]int{0, item.Len()}","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/funcs.go#L231-L267","documentation":"Raised by the `slice` action when the argument is a pointer that is non-nil in interface but points to nothing — `indirect` returns isNil=true at funcs.go:248-249. The template engine dereferences pointers automatically, but a nil `*[]T` or `*string` cannot be sliced because there is no underlying value.","triggerScenarios":"`{{slice .Ptr 0 1}}` where `.Ptr` is `*[]int` and is nil; passing a nil pointer to a slice builtin; a struct field typed `*string` that was never initialized.","commonSituations":"Go struct fields exposed to templates as pointer types for optional/omitempty semantics; JSON unmarshaling into pointer fields that were absent in the source; newer API returning pointer-to-slice where an older one returned slice directly.","solutions":["Initialize the pointer in Go before passing it to the template, or change the field from `*[]T`/`*string` to a value type.","Guard in the template: `{{with .Ptr}}{{slice . 0 1}}{{end}}` — `with` treats a nil pointer as false.","Return a non-nil zero value (empty slice/string) from the data layer instead of a nil pointer."],"exampleFix":"// before (Go)\ntype Data struct{ Items *[]string }\n// template\n{{slice .Items 0 5}}   // .Items is nil pointer -> error\n\n// after\n{{with .Items}}{{slice . 0 5}}{{end}}","handlingStrategy":"validation","validationCode":"// In template:\n//   {{with .Ptr}}{{slice . 0 1}}{{end}}\n// In Go, initialize pointer fields before rendering:\n//   if d.Items == nil { d.Items = &[]string{} }","typeGuard":"func nonNilPointer(v interface{}) bool {\n    rv := reflect.ValueOf(v)\n    return rv.IsValid() && rv.Kind() == reflect.Ptr && !rv.IsNil()\n}","tryCatchPattern":null,"preventionTips":["Prefer value types over pointer types for fields rendered in templates.","Initialize all pointer fields in the data constructor.","Use {{with}} to guard optional pointer fields."],"tags":["template","slice","nil-pointer","text-template"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}