{"record":{"id":"e4f1261a405cd3d1","repo":"gohugoio/hugo","slug":"can-t-index-item-of-type-s-e4f126","errorCode":null,"errorMessage":"can't index item of type %s","messagePattern":"can't index item of type (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/funcs.go","lineNumber":230,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\treturn reflect.Value{}, err\n\t\t\t}\n\t\t\titem = item.Index(x)\n\t\tcase reflect.Map:\n\t\t\tindex, err := prepareArg(index, item.Type().Key())\n\t\t\tif err != nil {\n\t\t\t\treturn reflect.Value{}, err\n\t\t\t}\n\t\t\tif x := item.MapIndex(index); x.IsValid() {\n\t\t\t\titem = x\n\t\t\t} else {\n\t\t\t\titem = reflect.Zero(item.Type().Elem())\n\t\t\t}\n\t\tcase reflect.Invalid:\n\t\t\t// the loop holds invariant: item.IsValid()\n\t\t\tpanic(\"unreachable\")\n\t\tdefault:\n\t\t\treturn reflect.Value{}, fmt.Errorf(\"can't index item of type %s\", item.Type())\n\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 {","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/funcs.go#L212-L248","documentation":"Raised by the `index` template action (e.g. `{{index .X 0}}`) when the target value's reflect.Kind is not Array, Slice, String, or Map. The index builtin only walks container types; anything else (struct, int, bool, func, chan) falls into the default branch at funcs.go:230 and is rejected. The %s is the offending value's Go type.","triggerScenarios":"`{{index .Foo 0}}` where `.Foo` is a struct, int, bool, pointer-to-struct (after indirect it derefs to struct), time.Time, or any non-container. Also `{{index . 5}}` on a scalar root, or chaining `{{index (index .Matrix 0) 0}}` when an inner step returns a struct.","commonSituations":"Front matter field declared as a string but template treats it as a list; a Hugo shortcode param resolved to a single value instead of the expected slice; paginating a non-slice; refactoring a Go struct field from `[]string` to a custom struct type without updating templates.","solutions":["Inspect the actual runtime type of the value with `{{printf \"%T\" .Foo}}` and compare against what the template assumes.","Switch the template from `index` to field/method access (`{{.Foo.Bar}}`) if the value is a struct.","Change the data passed in (the Go context or front matter) to a slice/array/map so indexing is valid.","Guard with `{{if reflect.IsSlice .Foo}}...{{end}}` or a custom helper before indexing."],"exampleFix":"// before\n{{index .Tags 0}}   // .Tags is a string, not []string\n\n// after\n{{.Tags}}            // string is used directly\n// or pass []string from Go: {{index .Tags 0}}","handlingStrategy":"type-guard","validationCode":"// In Go, before rendering, ensure container types:\n//   {{printf \"%T\" .Foo}} in template to inspect\n// In template, guard before indexing:\n//   {{if reflect.IsSlice .Foo}}{{index .Foo 0}}{{end}}","typeGuard":"// Expose a helper in FuncMap:\nfunc isIndexable(v interface{}) bool {\n    if v == nil { return false }\n    switch reflect.TypeOf(v).Kind() {\n    case reflect.Slice, reflect.Array, reflect.Map, reflect.String:\n        return true\n    }\n    return false\n}\n// template: {{if isIndexable .Foo}}{{index .Foo 0}}{{end}}","tryCatchPattern":null,"preventionTips":["Pass only container types (slice/array/map/string) into templates you intend to index.","Print the runtime type with {{printf \"%T\" .X}} when authoring index actions.","Keep Go struct fields stable: avoid flipping a slice field to a struct without auditing templates."],"tags":["template","reflection","index","text-template"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}