gohugoio/hugo · error
index out of range: %d
Error message
index out of range: %d
What it means
Returned by indexArg when the integer index is negative or exceeds the slice/array/string capacity (cap). Bounds are checked against cap (not len) so the message can fire on cap-relative out-of-range for slice expressions too. The %d is the offending index value.
Source
Thrown at tpl/internal/go_templates/texttemplate/funcs.go:188
}
return false
}
// indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible.
func indexArg(index reflect.Value, cap int) (int, error) {
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 0, fmt.Errorf("cannot index slice/array with nil")
default:
return 0, fmt.Errorf("cannot index slice/array with type %s", index.Type())
}
if x < 0 || int(x) < 0 || int(x) > cap {
return 0, fmt.Errorf("index out of range: %d", x)
}
return int(x), nil
}
// Indexing.
// index returns the result of indexing its first argument by the following
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
// indexed item must be a map, slice, or array.
func index(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
item = indirectInterface(item)
if !item.IsValid() {
return reflect.Value{}, fmt.Errorf("index of untyped nil")
}
for _, index := range indexes {
index = indirectInterface(index)
var isNil bool
if item, isNil = indirect(item); isNil {View on GitHub (pinned to 52c9bd7908)
Solutions
- Clamp/guard the index: {{if and (ge $i 0) (lt $i (len .Slice))}}{{index .Slice $i}}{{end}}.
- Validate ranges in the data layer before passing to the template.
- Use a helper func that bounds-checks and returns a default on out-of-range.
- For last-element access, compute len-1 explicitly and guard against empty slices.
Example fix
// before
{{index .Items (sub (len .Items) 1)}} // panics/errors when empty
// after
{{if .Items}}{{index .Items (sub (len .Items) 1)}}{{end}} Defensive patterns
Strategy: validation
Validate before calling
// register a bounds-safe accessor
template.Funcs(template.FuncMap{
"at": func(seq any, i int) any {
v := reflect.ValueOf(seq)
if i < 0 || i >= v.Len() { return nil }
return v.Index(i).Interface()
},
}) Prevention
- Guard indices: {{if and (ge $i 0) (lt $i (len .Slice))}}{{index .Slice $i}}{{end}}.
- Register a bounds-checked helper returning a default out of range.
- Validate user-supplied offsets before render.
When it happens
Trigger: Using {{index .Slice -1}} or {{index .Slice (sub (len .Slice) 1)}} that evaluates out of range; an index computed from user input that exceeds len; slicing past the end via the slice builtin.
Common situations: Off-by-one in computed indices; user-supplied page/offset numbers used unchecked; empty slice indexed at 0; negative index expected to count from end (Go does not support that).
Related errors
- cannot index slice/array with nil
- cannot index slice/array with type %s
- index of untyped nil
- index of nil pointer
- index of type %T with args %v failed: %s
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/8312787090cd3014.
Report an issue: GitHub.