{"record":{"id":"fc32b533e67ff320","repo":"gohugoio/hugo","slug":"can-t-index-item-of-type-s","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/collections/index.go","lineNumber":113,"sourceCode":"\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\tv = v.Index(int(x))\n\t\tcase reflect.Map:\n\t\t\tindex, err := prepareArg(index, v.Type().Key())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif x := v.MapIndex(index); x.IsValid() {\n\t\t\t\tv = x\n\t\t\t} else {\n\t\t\t\tv = reflect.Zero(v.Type().Elem())\n\t\t\t}\n\t\tcase reflect.Invalid:\n\t\t\t// the loop holds invariant: v.IsValid()\n\t\t\tpanic(\"unreachable\")\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"can't index item of type %s\", v.Type())\n\t\t}\n\t}\n\treturn v.Interface(), nil\n}\n\n// prepareArg checks if value can be used as an argument of type argType, and\n// converts an invalid value to appropriate zero if possible.\n//\n// Copied from Go stdlib src/text/template/funcs.go.\nfunc prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {\n\tif !value.IsValid() {\n\t\tif !canBeNil(argType) {\n\t\t\treturn reflect.Value{}, fmt.Errorf(\"value is nil; should be of type %s\", argType)\n\t\t}\n\t\tvalue = reflect.Zero(argType)\n\t}\n\tif !value.Type().AssignableTo(argType) {\n\t\treturn reflect.Value{}, fmt.Errorf(\"value has type %s; should be %s\", value.Type(), argType)","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/index.go#L95-L131","documentation":"Thrown inside doIndex when the item being indexed is reflect.Invalid-handled separately-or a kind that is neither Array, Slice, String, nor Map (e.g. struct, int, float, bool, func, chan). The item's reflect.Type is named via %s. This means the value itself is not indexable at all, regardless of the key supplied.","triggerScenarios":"Calling `{{ index 42 0 }}`, `{{ index $pageObject \"Title\" }}` (page is a struct, not indexable — use `.Title` field access instead), `{{ index 3.14 \"x\" }}`, or `{{ index $func 0 }}`. The default branch in doIndex's switch over v.Kind() catches all non-indexable kinds.","commonSituations":"Author assumes an object is a map when it is a struct (pages, resources are structs), or chains index past a scalar leaf. Common when traversing nested data where a path segment resolves to a primitive but indexing continues.","solutions":["Use field/method access for structs: `{{ .Title }}` instead of `{{ index . \"Title\" }}`.","Stop indexing once you reach a scalar leaf.","Convert the value to a map if generic key access is required.","Inspect the type named in the error to choose field vs index access."],"exampleFix":"// before\n{{ index .Page \"Title\" }}\n// after\n{{ .Page.Title }}","handlingStrategy":"type-guard","validationCode":"func isIndexableKind(v any) bool {\n    rv := reflect.ValueOf(v)\n    if !rv.IsValid() { return false }\n    switch rv.Kind() {\n    case reflect.Slice, reflect.Array, reflect.String, reflect.Map:\n        return true\n    }\n    return false\n}","typeGuard":"func isIndexableCollection(v any) bool {\n    return isIndexableKind(v)\n}","tryCatchPattern":null,"preventionTips":["Use field/method access (`.Field`) for structs instead of index.","Stop traversing once you reach a scalar leaf.","Confirm the value is a map/slice/array before indexing.","Inspect the named type in the error to choose access strategy."],"tags":["go","hugo","template","collections","index","type-error"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}