{"record":{"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/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/transform/unmarshal.go#L198-L222","documentation":"Thrown by stringToRune (tpl/transform/unmarshal.go:216), invoked while decoding CSV options. The Delimiter and Comment options must each be a single rune; a string with more than one character is rejected and the offending value is printed via %q. An empty string is allowed and maps to rune 0.","triggerScenarios":"Calling {{ transform.Unmarshal (dict \"format\" \"csv\" \"delimiter\" \";,\") $csv }} (multi-char delimiter) or passing a Comment string longer than one character.","commonSituations":"Assuming multi-character CSV delimiters are supported; copying a config snippet that wraps the delimiter in quotes incorrectly; passing a word like 'tab' instead of the literal character.","solutions":["Provide exactly one character for delimiter/comment, e.g. \"delimiter\" \";\"","For tab, use the literal \"\\t\" (single rune)","Pre-split multi-character input outside the template before unmarshaling"],"exampleFix":"// before\n{{ transform.Unmarshal (dict \"format\" \"csv\" \"delimiter\" \";,\") $csv }}\n// after\n{{ transform.Unmarshal (dict \"format\" \"csv\" \"delimiter\" \";\") $csv }}","handlingStrategy":"validation","validationCode":"func validSingleRune(s string) bool {\n    return len([]rune(s)) <= 1\n}\n// before building options:\nif d, ok := opts[\"delimiter\"]; ok && !validSingleRune(fmt.Sprint(d)) {\n    return errors.New(\"csv delimiter must be a single character\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a single literal character for CSV delimiter/comment options","Use \"\\t\" for tab rather than the word 'tab'","Validate option length before passing to transform.Unmarshal"],"tags":["template","transform","unmarshal","csv","delimiter"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}