{"id":"e6955b5325ef8ff4","repo":"gohugoio/hugo","slug":"invalid-character-q","errorCode":null,"errorMessage":"invalid character: %q","messagePattern":"invalid character: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/transform/unmarshal.go","lineNumber":216,"sourceCode":"}\n\nfunc stringToRune(v any) (rune, error) {\n\ts, err := cast.ToStringE(v)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif len(s) == 0 {\n\t\treturn 0, nil\n\t}\n\n\tvar r rune\n\n\tfor i, rr := range s {\n\t\tif i == 0 {\n\t\t\tr = rr\n\t\t} else {\n\t\t\treturn 0, fmt.Errorf(\"invalid character: %q\", v)\n\t\t}\n\t}\n\n\treturn r, nil\n}\n","sourceCodeStart":198,"sourceCodeEnd":222,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/transform/unmarshal.go#L198-L222","documentation":"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.","triggerScenarios":"Calling `transform.Unmarshal (dict \"delimiter\" \";;\") $csv` or `dict \"comment\" \"//\"` — any Delimiter/Comment option string longer than one character.","commonSituations":"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.","solutions":["Use exactly one character: `dict \"delimiter\" \";\"` or `dict \"comment\" \"#\"`.","For tab-delimited data, pass a literal tab: `dict \"delimiter\" \"\\t\"`.","Pre-process the data (e.g. `replace`) if the source truly uses a multi-character separator."],"exampleFix":"{{/* before */}}\n{{ $d := transform.Unmarshal (dict \"delimiter\" \"::\") $csv }}\n{{/* after */}}\n{{ $csv = replace $csv \"::\" \";\" }}\n{{ $d := transform.Unmarshal (dict \"delimiter\" \";\") $csv }}","handlingStrategy":"validation","validationCode":"{{/* CSV delimiter option must be exactly one character */}}\n{{ $opts := dict \"delimiter\" \";\" }}\n{{ if ne (len $opts.delimiter) 1 }}{{ errorf \"delimiter must be a single character\" }}{{ end }}\n{{ $data := transform.Unmarshal $opts $csv }}","typeGuard":null,"tryCatchPattern":"{{ with try (transform.Unmarshal (dict \"delimiter\" $d \"comment\" $c) $csv) }}\n  {{ with .Err }}{{ errorf \"bad CSV option: %s\" . }}{{ end }}\n{{ end }}","preventionTips":["Pass CSV options 'delimiter' and 'comment' as single-character strings only (e.g. \",\" or \";\"), never multi-character or empty strings","Keep option values literal in the template rather than computed from user data","Consult the transform.Unmarshal docs for the exact option map shape before using CSV options"],"tags":["hugo","templates","csv","unmarshal","options"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}