gohugoio/hugo · error
cannot index slice/array with type %s
Error message
cannot index slice/array with type %s
What it means
Thrown inside doIndex (surfaced via the Index wrapper) when indexing an array, slice, or string with a reflect.Kind that is not an integer and not Invalid (nil has its own message). Only signed/unsigned integer kinds are accepted as positional indices; floats, strings, bools, structs, etc. are rejected with the index's reflect.Type named via %s.
Source
Thrown at tpl/collections/index.go:90
index := reflect.ValueOf(i)
var isNil bool
if v, isNil = hreflect.Indirect(v); isNil {
// See issue 10489
// This used to be an error.
return nil, nil
}
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
var x int64
switch index.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
x = index.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
x = int64(index.Uint())
case reflect.Invalid:
return nil, errors.New("cannot index slice/array with nil")
default:
return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
}
if x < 0 || x >= int64(v.Len()) {
// We deviate from stdlib here. Don't return an error if the
// index is out of range.
return nil, nil
}
v = v.Index(int(x))
case reflect.Map:
index, err := prepareArg(index, v.Type().Key())
if err != nil {
return nil, err
}
if x := v.MapIndex(index); x.IsValid() {
v = x
} else {
v = reflect.Zero(v.Type().Elem())
}View on GitHub (pinned to 52c9bd7908)
Solutions
- Coerce the key to an integer before indexing: `{{ index $slice (int $k) }}`.
- Use integer literals directly: `{{ index $slice 2 }}`.
- If the key arrives as a string from JSON, convert upstream in a content adapter or partial.
- Switch to a map if string keys are genuinely needed.
Example fix
// before
{{ index $slice "1" }}
// after
{{ index $slice 1 }} Defensive patterns
Strategy: type-guard
Validate before calling
func isIntegerKind(v any) bool {
k := reflect.ValueOf(v).Kind()
switch k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return true
}
return false
} Type guard
func isValidSliceIndex(k any) bool {
return isIntegerKind(k)
} Prevention
- Use integer literals for slice/array/string indices.
- Coerce string-encoded numbers with int() before indexing slices.
- Standardize JSON/CSV indices as integers at ingestion.
- Use a map if you genuinely need string keys.
When it happens
Trigger: Calling `{{ index $slice "0" }}` (string key), `{{ index $slice 1.5 }}` (float), `{{ index $str true }}`, or `{{ index $array $someStruct }}`. The switch in doIndex over index.Kind only accepts int*/uint* families; everything non-nil falls to the default branch producing this error.
Common situations: Front matter supplies indices as strings ("0") which are not auto-coerced for slices (unlike maps), computed float indices, or template variables typed as interface{} holding a string. Frequent when data crosses JSON boundaries where numbers may arrive as strings.
Related errors
- can't index item of type %s
- value has type %s; should be %s
- isset unable to use key of type %T as index
- type %T not supported
- arguments to complement must be slices or arrays
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/f3b4cf55971c9278.
Report an issue: GitHub.