gohugoio/hugo · error
too few arguments
Error message
too few arguments
What it means
Hugo's `strings.Substr` requires at least a start position after the string; with zero variadic arguments there is nothing to extract, so it fails fast with "too few arguments" rather than returning the whole string.
Source
Thrown at tpl/strings/strings.go:396
// To extract characters from the end of the string, use a negative start number.
//
// In addition, borrowing from the extended behavior described at http://php.net/substr,
// if length is given and is negative, then that many characters will be omitted from
// the end of string.
func (ns *Namespace) Substr(a any, nums ...any) (string, error) {
s, err := cast.ToStringE(a)
if err != nil {
return "", err
}
asRunes := []rune(s)
rlen := len(asRunes)
var start, length int
switch len(nums) {
case 0:
return "", errors.New("too few arguments")
case 1:
if start, err = cast.ToIntE(nums[0]); err != nil {
return "", errors.New("start argument must be an integer")
}
length = rlen
case 2:
if start, err = cast.ToIntE(nums[0]); err != nil {
return "", errors.New("start argument must be an integer")
}
if length, err = cast.ToIntE(nums[1]); err != nil {
return "", errors.New("length argument must be an integer")
}
default:
return "", errors.New("too many arguments")
}
if rlen == 0 {
return "", nilView on GitHub ↗ (pinned to 8a468df065)
Solutions
- Provide at least a start index: `{{ substr "hello" 1 }}`
- Provide start and length for a bounded extract: `{{ substr "hello" 1 3 }}`
- If you just wanted the whole string, drop the `substr` call entirely
Example fix
// before
{{ substr .Title }}
// after
{{ substr .Title 0 10 }} Defensive patterns
Strategy: validation
Validate before calling
{{/* truncate needs at least a length: */}}
{{ if and .len .text }}{{ truncate .len .text }}{{ end }} Try / catch
{{ with try (truncate .len .text) }}{{ if .Err }}{{ errorf "truncate misuse: %s" .Err }}{{ end }}{{ end }} Prevention
- Always pass both the length and the text — in pipe form `{{ .Summary | truncate 70 }}` the piped value supplies the text.
- Verify optional params exist with `default` before building the call: `truncate (default 70 .Params.summaryLen) .Summary`.
- Build with `hugo` in CI so arity errors fail the build rather than shipping.
When it happens
Trigger: Calling `substr` with only the string: `{{ substr "hello" }}`, or a pipeline like `{{ .Title | substr }}` where no start/length arguments are given.
Common situations: Confusing `substr` with functions that have sensible no-arg defaults; refactoring a template and dropping the index arguments; dynamically built calls where a param evaluated to nothing.
Related errors
- too many arguments
- need at least 2 arguments to append
- must provide a Resource and optionally an options map
- operator argument must be string type
- can't evaluate the array by no match argument or more than o
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/4f79ab9e3a8f18e9.json.
Report an issue: GitHub ↗.