gohugoio/hugo · error

truncate requires a length and a string

Error message

truncate requires a length and a string

What it means

Hugo's `truncate` takes the length first, then optionally an ellipsis, then the text. If only the length is supplied and no text argument follows (zero options), there is nothing to truncate, so it errors out. Note the piped value counts as the final argument.

Source

Thrown at tpl/strings/truncate.go:54

type htmlTag struct {
	name    string
	pos     int
	openTag bool
}

// Truncate truncates the string in s to the specified length.
func (ns *Namespace) Truncate(s any, options ...any) (template.HTML, error) {
	length, err := cast.ToIntE(s)
	if err != nil {
		return "", err
	}
	var textParam any
	var ellipsis string

	switch len(options) {
	case 0:
		return "", errors.New("truncate requires a length and a string")
	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 {

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Add the text argument: `{{ truncate 30 .Summary }}` or pipe it: `{{ .Summary | truncate 30 }}`
  2. Check the argument order — the length must come first
  3. If the text can be empty/nil on some pages, wrap in `{{ with .Summary }}{{ truncate 30 . }}{{ end }}`

Example fix

// before
{{ truncate 30 }}
// after
{{ truncate 30 .Summary }}
Defensive patterns

Strategy: validation

Validate before calling

{{ if and (isset . "len") .text }}
  {{ truncate (int .len) (string .text) }}
{{ end }}

Type guard

{{/* ensure first arg is a number, last is a string */}}
{{ $ok := and (in (slice "int" "int64" "float64") (printf "%T" .len)) (eq (printf "%T" .text) "string") }}

Try / catch

{{ with try (truncate .len .text) }}{{ if .Err }}{{ warnf "truncate: %s" .Err }}{{ .text }}{{ else }}{{ .Value }}{{ end }}{{ end }}

Prevention

When it happens

Trigger: `{{ truncate 30 }}` with no text and nothing piped in, or building the call dynamically so the text argument ends up missing.

Common situations: Forgetting that argument order is length-first (`truncate 30 .Summary`, not `truncate .Summary 30` — the latter fails earlier at the int cast); dropping the piped value when refactoring `{{ .Summary | truncate 30 }}`; partials called without the expected text parameter.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/8fd4b9f09596b5dd.json. Report an issue: GitHub ↗.