{"record":{"id":"9ec53199825e0425","repo":"antonmedv/fx","slug":"unexpected-character-q-in-object","errorCode":null,"errorMessage":"Unexpected character %q in object","messagePattern":"Unexpected character %q in object","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/jsonx/json.go","lineNumber":391,"sourceCode":"\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif p.char == '}' {\n\t\t\tcloseBracket := &Node{\n\t\t\t\tKind:       Object,\n\t\t\t\tDepth:      p.depth,\n\t\t\t\tLineNumber: p.lineNumberPlusPlus(),\n\t\t\t}\n\t\t\tcloseBracket.Value = curlyBracketClose\n\t\t\tcloseBracket.Parent = object\n\t\t\tcloseBracket.Index = -1\n\t\t\tobject.Append(closeBracket)\n\t\t\tp.next()\n\t\t\treturn object\n\t\t}\n\n\t\tpanic(fmt.Sprintf(\"Unexpected character %q in object\", p.char))\n\t}\n}\n\nfunc (p *JsonParser) parseArray() *Node {\n\tarr := &Node{\n\t\tKind:       Array,\n\t\tDepth:      p.depth,\n\t\tLineNumber: p.lineNumberPlusPlus(),\n\t}\n\tarr.Value = squareBracketOpen\n\n\tp.next()\n\tp.skipWhitespace()\n\n\tif p.char == ']' {\n\t\tarr.Value = squareBracketPair\n\t\tp.next()\n\t\treturn arr","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/antonmedv/fx/blob/4f31cd3a0c5d66f1b4290a2719bab14a5cee8ebe/internal/jsonx/json.go#L373-L409","documentation":"While iterating over object members, after a value the parser expects either ',' (next member) or '}' (close object). If the character is neither, it panics with \"Unexpected character %q in object\". This catches malformed separators and garbage between members.","triggerScenarios":"Parsing {\"a\":1 \"b\":2} (missing comma), {\"a\":1; \"b\":2}, {\"a\":1 c}, or any stray character after a member value inside an object.","commonSituations":"Hand-edited JSON with a dropped comma between key/value pairs; copy-paste from JS object literals using ';' or newline-separated members; corrupted or truncated files with stray bytes.","solutions":["Add the missing comma between members: {\"a\":1 \"b\":2} -> {\"a\":1, \"b\":2}","Remove any stray characters after the value that are not ',' or '}'","Re-run the document through a JSON formatter to identify the malformed spot","Check for encoding/corruption issues (e.g. binary bytes in the file)"],"exampleFix":"// before\n{\"a\": 1 \"b\": 2}\n\n// after\n{\"a\": 1, \"b\": 2}","handlingStrategy":"validation","validationCode":"func validateArrayCommas(src string) error {\n\t// inside '[', after a value only ',' or ']' may appear; quick heuristic check\n\tinArr, inStr, esc, prev := 0, false, false, byte(0)\n\tfor i := 0; i < len(src); i++ {\n\t\tc := src[i]\n\t\tif inStr { if esc { esc = false } else if c == '\\\\' { esc = true } else if c == '\"' { inStr = false }; continue }\n\t\tswitch c {\n\t\tcase '\"': inStr = true\n\t\tcase '[': inArr++\n\t\tcase ']': if inArr > 0 { inArr-- }\n\t\t}\n\t\tif inArr > 0 && (prev=='\"'||isDigit(prev)) && isValueStart(c) && c != ',' {\n\t\t\treturn fmt.Errorf(\"missing ',' between array elements at offset %d\", i)\n\t\t}\n\t\tprev = c\n\t}\n\treturn nil\n}\nfunc isDigit(c byte) bool { return c >= '0' && c <= '9' }\nfunc isValueStart(c byte) bool { return isDigit(c) || c=='\"' || c=='t' || c=='f' || c=='n' || c=='{' || c=='[' }","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\terr = fmt.Errorf(\"json parse failed (bad array separator?): %v\", r)\n\t\t}\n\t}()\n\troot = p.Parse(data)\n\treturn\n}","preventionTips":["Generate arrays with a serializer rather than joining strings","Always separate elements with ',' — check joins in template code","Lint all JSON artifacts in CI","When editing arrays by hand, re-validate after each edit"],"tags":["json","parser","syntax-error"],"backgroundTag":"invalid-json-syntax","analyzedSha":"4f31cd3a0c5d66f1b4290a2719bab14a5cee8ebe","analyzedAt":"2026-09-02T02:17:47.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}