gohugoio/hugo · error
cannot 3-index slice a string
Error message
cannot 3-index slice a string
What it means
Raised by the `slice` action specifically when the item is a string and exactly three indexes are given (funcs.go:257-258). Go does not permit 3-index slice expressions on strings (`s[i:j:k]` is only valid for arrays/slices), so the template engine rejects it up front.
Source
Thrown at tpl/internal/go_templates/texttemplate/funcs.go:258
// is x[:], "slice x 1" is x[1:], and "slice x 1 2 3" is x[1:2:3]. The first
// argument must be a string, slice, or array.
func slice(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
item = indirectInterface(item)
if !item.IsValid() {
return reflect.Value{}, fmt.Errorf("slice of untyped nil")
}
var isNil bool
if item, isNil = indirect(item); isNil {
return reflect.Value{}, fmt.Errorf("slice of nil pointer")
}
if len(indexes) > 3 {
return reflect.Value{}, fmt.Errorf("too many slice indexes: %d", len(indexes))
}
var cap int
switch item.Kind() {
case reflect.String:
if len(indexes) == 3 {
return reflect.Value{}, fmt.Errorf("cannot 3-index slice a string")
}
cap = item.Len()
case reflect.Array, reflect.Slice:
cap = item.Cap()
default:
return reflect.Value{}, fmt.Errorf("can't slice item of type %s", item.Type())
}
// set default values for cases item[:], item[i:].
idx := [3]int{0, item.Len()}
for i, index := range indexes {
x, err := indexArg(index, cap)
if err != nil {
return reflect.Value{}, err
}
idx[i] = x
}
// given item[i:j], make sure i <= j.
if idx[0] > idx[1] {View on GitHub (pinned to 52c9bd7908)
Solutions
- Drop the third index for strings: `{{slice .Str 0 2}}`.
- If you really need cap-bounded slicing, convert to `[]byte`/`[]rune` in Go first.
Example fix
// before
{{slice .Name 0 3 5}} // .Name is string
// after
{{slice .Name 0 3}} Defensive patterns
Strategy: validation
Validate before calling
// For strings, use at most 2 indexes:
// {{slice .Str 0 3}}
// If you need cap semantics, operate on []byte in Go first. Type guard
func isString(v interface{}) bool {
return v != nil && reflect.TypeOf(v).Kind() == reflect.String
} Prevention
- Never pass 3 indexes to slice when the operand is a string.
- Distinguish string from []byte at the data boundary.
When it happens
Trigger: `{{slice .Str 0 2 4}}` where `.Str` is a string; trying to bound a string sub-slice's capacity like an array.
Common situations: Treating a string like a `[]byte`; helper template written for slices being reused on strings; front matter that changed from a byte slice to a string.
Related errors
- slice of untyped nil
- slice of nil pointer
- too many slice indexes: %d
- can't slice item of type %s
- invalid slice index: %d > %d
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/d6b484bacb6ffa5d.
Report an issue: GitHub.