{"record":{"id":"631a3770cdeefea2","repo":"gohugoio/hugo","slug":"isset-unable-to-use-key-of-type-t-as-index","errorCode":null,"errorMessage":"isset unable to use key of type %T as index","messagePattern":"isset unable to use key of type %T as index","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/collections.go","lineNumber":340,"sourceCode":"\n\tif g, ok := in.(collections.Grouper); ok {\n\t\treturn g.Group(key, items)\n\t}\n\n\treturn nil, fmt.Errorf(\"grouping not supported for type %T %T\", items, in)\n}\n\n// IsSet returns whether a given array, channel, slice, or map in c has the given key\n// defined.\nfunc (ns *Namespace) IsSet(c any, key any) (bool, error) {\n\tav := reflect.ValueOf(c)\n\tkv := reflect.ValueOf(key)\n\n\tswitch av.Kind() {\n\tcase reflect.Array, reflect.Chan, reflect.Slice:\n\t\tk, err := cast.ToIntE(key)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"isset unable to use key of type %T as index\", key)\n\t\t}\n\t\tif av.Len() > k {\n\t\t\treturn true, nil\n\t\t}\n\tcase reflect.Map:\n\t\tif kv.Type() == av.Type().Key() {\n\t\t\treturn av.MapIndex(kv).IsValid(), nil\n\t\t}\n\tdefault:\n\t\tns.deps.Log.Warnf(\"calling IsSet with unsupported type %q (%T) for key %v will always return false.\\n\", av.Kind(), c, key)\n\t}\n\n\treturn false, nil\n}\n\n// Last returns the last limit items in the list l.\nfunc (ns *Namespace) Last(limit any, l any) (any, error) {\n\tif limit == nil || l == nil {","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/collections.go#L322-L358","documentation":"Thrown by Hugo's `isset` template function (Namespace.IsSet) when the collection argument is an array, channel, or slice but the supplied key cannot be converted to an integer index via cast.ToIntE. Arrays/slices/channels are positional, so a numeric index is mandatory; any other key type (string, struct, map, bool) is meaningless as a positional lookup and is rejected. The %T verb fills in the actual Go type of the offending key.","triggerScenarios":"Calling `{{ isset $slice \"foo\" }}`, `{{ isset .Pages \"title\" }}`, or `{{ isset $array $someStruct }}` — i.e. passing a non-integer second argument where the first is an array/slice/chan. Also triggers when the key is a float like 1.5 (cast.ToIntE rejects it) or a numeric string that cast cannot coerce.","commonSituations":"Template author confuses a slice with a map (e.g. treats `.Pages` as key-addressable by string), passes front-matter string keys to a positional collection, or flows an `interface{}` whose dynamic type is a string into `isset` against a slice. Common during partial refactors where a map was replaced by a slice but template calls were not updated.","solutions":["Pass an integer literal or integer-typed value as the key, e.g. `{{ isset $slice 0 }}`.","If you meant string-key lookup, ensure the first argument is a map (`map[string]...`), not a slice/array.","If the key is dynamic, coerce it to int before the call: `{{ $k := int $key }}{{ isset $slice $k }}`.","Guard the call with a type check or restructure data so the same collection is always addressed by index."],"exampleFix":"// before\n{{ if isset .Pages \"title\" }}...{{ end }}\n// after\n{{ if isset .Pages 0 }}...{{ end }}\n// or, if the collection is actually a map:\n{{ if isset .Params \"title\" }}...{{ end }}","handlingStrategy":"validation","validationCode":"// Validate key is int before IsSet on an array/slice/chan.\nfunc isSetIntKey(c, key any) bool {\n    v := reflect.ValueOf(c)\n    if k := v.Kind(); k == reflect.Array || k == reflect.Slice || k == reflect.Chan {\n        if n, err := cast.ToIntE(key); err == nil {\n            return v.Len() > n\n        }\n        return false // would trigger the error; bail out\n    }\n    // fall through to map handling\n    return false\n}","typeGuard":"func isIndexableByKey(c any) bool {\n    v := reflect.ValueOf(c)\n    switch v.Kind() {\n    case reflect.Array, reflect.Slice, reflect.Chan:\n        return true\n    case reflect.Map:\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Always pass an integer literal or int-typed variable when calling isset on a slice/array/chan.","Distinguish map-keyed collections (.Params) from positional ones (.Pages) at the template level.","If the key is dynamic, coerce it with int() before isset.","Document collection shapes in partial signatures so callers pass correct key types."],"tags":["go","hugo","template","collections","isset","type-error"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}