{"record":{"id":"47e966043a2cde00","repo":"antonmedv/fx","slug":"unexpected-character-q-in-keyword","errorCode":null,"errorMessage":"Unexpected character %q in keyword","messagePattern":"Unexpected character %q in keyword","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/jsonx/json.go","lineNumber":462,"sourceCode":"\t\t\t}\n\t\t\tcloseBracket.Value = squareBracketClose\n\t\t\tcloseBracket.Parent = arr\n\t\t\tcloseBracket.Index = -1\n\t\t\tarr.Append(closeBracket)\n\t\t\tp.next()\n\t\t\treturn arr\n\t\t}\n\n\t\tpanic(fmt.Sprintf(\"Invalid character %q in array\", p.char))\n\t}\n}\n\nfunc (p *JsonParser) parseKeyword(name string, kind Kind) *Node {\n\tstart := p.end - 1\n\tfor i := 1; i < len(name); i++ {\n\t\tp.next()\n\t\tif p.char != name[i] {\n\t\t\tpanic(fmt.Sprintf(\"Unexpected character %q in keyword\", p.char))\n\t\t}\n\t}\n\tp.next()\n\tif isEndOfValue(p.char) {\n\t\tkeyword := &Node{\n\t\t\tKind:       kind,\n\t\t\tDepth:      p.depth,\n\t\t\tValue:      string(p.data[start : p.end-1]),\n\t\t\tLineNumber: p.lineNumberPlusPlus(),\n\t\t}\n\t\treturn keyword\n\t}\n\n\tpanic(fmt.Sprintf(\"Unexpected character %q in keyword\", p.char))\n}\n\nfunc (p *JsonParser) parseNullOrNan() *Node {\n\tp.next()","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/antonmedv/fx/blob/4f31cd3a0c5d66f1b4290a2719bab14a5cee8ebe/internal/jsonx/json.go#L444-L480","documentation":"parseKeyword matches literal keywords (true, false, null) character by character. If the character at position i does not match the expected letter of the keyword, the parser panics with \"Unexpected character %q in keyword\". This detects misspelled or truncated keywords like tru, nul, or falsy. The source region shows this fires inside the matching loop when p.char != name[i].","triggerScenarios":"Parsing inputs such as tru, treu, nul1, fals, or nullx's first mismatch char, e.g. 't' followed by anything other than 'r', entered parseKeyword via parseValue; also NaN handled separately in non-strict mode.","commonSituations":"Hand-edited JSON with typos in true/false/null; case mismatches like True/TRUE (JSON is case-sensitive); template glitches producing partial keywords; OCR or transcription errors in config.","solutions":["Spell the keyword exactly lowercase: true, false, null (not True, tru, Null)","Fix case-sensitivity errors (True -> true)","If a boolean/string was intended, quote non-keyword values: \"True\"","Validate with a JSON linter before parsing"],"exampleFix":"// before\n{\"enabled\": True}\n\n// after\n{\"enabled\": true}","handlingStrategy":"validation","validationCode":"func validateKeywords(src string) error {\n\t// reject non-lowercase or misspelled literals outside strings\n\ttokens := []string{\"true\", \"false\", \"null\"}\n\tre := regexp.MustCompile(`(?<![\"\\w])([TtFfNn][A-Za-z]*)`)\n\tinStr := false\n\tfor i := 0; i < len(src); i++ {\n\t\tif src[i] == '\"' { inStr = !inStr; continue }\n\t\tif inStr { continue }\n\t\trest := src[i:]\n\t\tloc := re.FindStringIndex(rest)\n\t\tif loc != nil && loc[0] == 0 {\n\t\t\tword := rest[loc[0]:loc[1]]\n\t\t\tok := false\n\t\t\tfor _, t := range tokens { if word == t { ok = true } }\n\t\t\tif !ok { return fmt.Errorf(\"invalid literal %q at offset %d (use lowercase true/false/null)\", word, i) }\n\t\t\ti += loc[1] - 1\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"func safeParse(p *jsonx.JsonParser, data []byte) (root *jsonx.Node, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif strings.Contains(fmt.Sprint(r), \"in keyword\") {\n\t\t\t\terr = fmt.Errorf(\"misspelled literal keyword: %v\", r)\n\t\t\t\treturn\n\t\t\t}\n\t\t\terr = fmt.Errorf(\"json parse failed: %v\", r)\n\t\t}\n\t}()\n\troot = p.Parse(data)\n\treturn\n}","preventionTips":["JSON literals are lowercase — never write True/False/Null/TRUE","Search configs for common typos (tru, flase, nul) with grep before deployment","Quote non-keyword words as strings if that was the intent","Run a JSON linter as a pre-commit hook"],"tags":["json","parser","keyword","case-sensitivity"],"backgroundTag":"invalid-json-syntax","analyzedSha":"4f31cd3a0c5d66f1b4290a2719bab14a5cee8ebe","analyzedAt":"2026-09-02T02:17:47.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}