gohugoio/hugo · error
text must be a string
Error message
text must be a string
What it means
Hugo's `truncate` template function casts its text argument to a string with `cast.ToStringE` after parsing the length and optional ellipsis. If that cast fails — i.e. the value passed as the text is not string-convertible (a map, slice, Page object, etc.) — Truncate returns this error. It fires only after the length argument was successfully parsed as an int, so it specifically means the second (or third) argument is the wrong type.
Source
Thrown at tpl/strings/truncate.go:73
case 1:
textParam = options[0]
ellipsis = " …"
case 2:
textParam = options[1]
ellipsis, err = cast.ToStringE(options[0])
if err != nil {
return "", errors.New("ellipsis must be a string")
}
if _, ok := options[0].(template.HTML); !ok {
ellipsis = html.EscapeString(ellipsis)
}
default:
return "", errors.New("too many arguments passed to truncate")
}
text, err := cast.ToStringE(textParam)
if err != nil {
return "", errors.New("text must be a string")
}
_, isHTML := textParam.(template.HTML)
if utf8.RuneCountInString(text) <= length {
if isHTML {
return template.HTML(text), nil
}
return template.HTML(html.EscapeString(text)), nil
}
tags := []htmlTag{}
var lastWordIndex, lastNonSpace, currentLen, endTextPos, nextTag int
for i, r := range text {
if i < nextTag {
continue
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Ensure the text argument is a string: pass `.Summary`, `.Plain`, or a string param, not an object or slice.
- Check argument order — it's `truncate LENGTH [ELLIPSIS] TEXT`; the text comes last.
- Convert explicitly before truncating, e.g. `{{ truncate 50 (string .Params.title) }}` or `delimit` a slice into a string first.
Example fix
<!-- before -->
{{ truncate 50 .Params.tags }}
<!-- after -->
{{ truncate 50 (delimit .Params.tags ", ") }} Defensive patterns
Strategy: type-guard
Validate before calling
{{ $v := .Params.summary }}
{{ if eq (printf "%T" $v) "string" }}{{ truncate 50 $v }}{{ end }} Type guard
{{/* narrow to string before truncate */}}
{{ $s := "" }}
{{ with $v }}{{ $s = printf "%v" . }}{{ end }}
{{ truncate 50 $s }} Prevention
- Pass only string values to truncate; convert numbers/slices first with printf "%v" or string
- Remember truncate accepts template.HTML too, but not maps/slices
- When truncating front-matter params, guard with `with` since missing params are nil
When it happens
Trigger: Calling `{{ truncate 50 .Params.items }}` where the value is a slice/map; passing arguments in the wrong order like `{{ truncate .Summary 50 }}` (string first, so length cast fails earlier, but e.g. `{{ truncate 50 "..." .Pages }}` hits this); piping a non-string value: `{{ .Pages | truncate 10 }}`.
Common situations: Front-matter params that are lists or maps instead of strings; piping a Page or Resource object instead of `.Content`/`.Summary`; refactoring a template and swapping argument order; a param that is sometimes a string and sometimes a list across content files.
Related errors
- arguments to symdiff must be slices or arrays
- can't iterate over %T
- start argument must be integer
- end argument must be integer
- too many arguments
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/664305ca40fc71e0.json.
Report an issue: GitHub ↗.