{"record":{"id":"05863a6439841bb1","repo":"gohugoio/hugo","slug":"malformed-character-constant-s","errorCode":null,"errorMessage":"malformed character constant: %s","messagePattern":"malformed character constant: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/parse/node.go","lineNumber":642,"sourceCode":"\tIsFloat    bool       // Number has a floating-point value.\n\tIsComplex  bool       // Number is complex.\n\tInt64      int64      // The signed integer value.\n\tUint64     uint64     // The unsigned integer value.\n\tFloat64    float64    // The floating-point value.\n\tComplex128 complex128 // The complex value.\n\tText       string     // The original textual representation from the input.\n}\n\nfunc (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {\n\tn := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}\n\tswitch typ {\n\tcase itemCharConstant:\n\t\trune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif tail != \"'\" {\n\t\t\treturn nil, fmt.Errorf(\"malformed character constant: %s\", text)\n\t\t}\n\t\tn.Int64 = int64(rune)\n\t\tn.IsInt = true\n\t\tn.Uint64 = uint64(rune)\n\t\tn.IsUint = true\n\t\tn.Float64 = float64(rune) // odd but those are the rules.\n\t\tn.IsFloat = true\n\t\treturn n, nil\n\tcase itemComplex:\n\t\t// fmt.Sscan can parse the pair, so let it do the work.\n\t\tif _, err := fmt.Sscan(text, &n.Complex128); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tn.IsComplex = true\n\t\tn.simplifyComplex()\n\t\treturn n, nil\n\t}\n\t// Imaginary constants can only be complex unless they are zero.","sourceCodeStart":624,"sourceCodeEnd":660,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/parse/node.go#L624-L660","documentation":"The Go template parser rejects malformed rune/character constants. For an itemCharConstant it calls strconv.UnquoteChar and requires the remaining tail to be a closing single quote; any leftover text is a malformed character constant. See node.go:636-643.","triggerScenarios":"A template literal such as {{ 'ab' }} (multi-rune), {{ '\\u000G' }} (invalid escape), or a stray character constant with trailing characters.","commonSituations":"Copy-pasting Go syntax into templates expecting char semantics; editor auto-completion inserting characters; attempting to express a single quote literal incorrectly.","solutions":["Use a double-quoted string literal instead of a single-quoted char constant for multi-character text.","Ensure single-quoted literals contain exactly one valid rune with correct escape syntax.","Fix or remove invalid Unicode escape sequences in the char constant."],"exampleFix":"// before\n{{ 'ab' }}\n\n// after\n{{ \"ab\" }}","handlingStrategy":"validation","validationCode":"// Validate char literals before relying on a generated template.\nfunc validCharLit(s string) bool {\n    if len(s) < 3 || s[0] != '\\'' || s[len(s)-1] != '\\'' { return false }\n    _, _, tail, err := strconv.UnquoteChar(s[1:], '\\'')\n    return err == nil && tail == \"'\"\n}","typeGuard":null,"tryCatchPattern":"_, err := template.New(\"t\").Parse(body)\nif err != nil {\n    // err contains the file:line; surface to the author\n    return err\n}","preventionTips":["Prefer double-quoted string literals for any text longer than one rune.","Lint templates during CI to catch malformed constants early."],"tags":["template","go","parse","syntax","rune"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}