gohugoio/hugo · error

invalid character: %q

Error message

invalid character: %q

What it means

The `delimiter` or `comment` option passed to `transform.Unmarshal` for CSV decoding must be a single character (one rune). Hugo converts the option string to a rune in `stringToRune`; if the string contains more than one rune, this error is raised showing the offending value.

Source

Thrown at tpl/transform/unmarshal.go:216

}

func stringToRune(v any) (rune, error) {
	s, err := cast.ToStringE(v)
	if err != nil {
		return 0, err
	}

	if len(s) == 0 {
		return 0, nil
	}

	var r rune

	for i, rr := range s {
		if i == 0 {
			r = rr
		} else {
			return 0, fmt.Errorf("invalid character: %q", v)
		}
	}

	return r, nil
}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Use exactly one character: `dict "delimiter" ";"` or `dict "comment" "#"`.
  2. For tab-delimited data, pass a literal tab: `dict "delimiter" "\t"`.
  3. Pre-process the data (e.g. `replace`) if the source truly uses a multi-character separator.

Example fix

{{/* before */}}
{{ $d := transform.Unmarshal (dict "delimiter" "::") $csv }}
{{/* after */}}
{{ $csv = replace $csv "::" ";" }}
{{ $d := transform.Unmarshal (dict "delimiter" ";") $csv }}
Defensive patterns

Strategy: validation

Validate before calling

{{/* CSV delimiter option must be exactly one character */}}
{{ $opts := dict "delimiter" ";" }}
{{ if ne (len $opts.delimiter) 1 }}{{ errorf "delimiter must be a single character" }}{{ end }}
{{ $data := transform.Unmarshal $opts $csv }}

Try / catch

{{ with try (transform.Unmarshal (dict "delimiter" $d "comment" $c) $csv) }}
  {{ with .Err }}{{ errorf "bad CSV option: %s" . }}{{ end }}
{{ end }}

Prevention

When it happens

Trigger: Calling `transform.Unmarshal (dict "delimiter" ";;") $csv` or `dict "comment" "//"` — any Delimiter/Comment option string longer than one character.

Common situations: Trying to use multi-character delimiters ("::", "\t " with stray whitespace), using "//" as a comment prefix out of habit from code, or accidentally passing an escaped sequence that expands to multiple characters.

Related errors


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