{"record":{"id":"a61b42ff0788059e","repo":"can1357/oh-my-pi","slug":"unterminated-object","errorCode":null,"errorMessage":"Unterminated object","messagePattern":"Unterminated object","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/json-parse.ts","lineNumber":259,"sourceCode":"\t\tif (c === '\"' || c === \"'\") return this.#string(s.charCodeAt(this.#i));\n\t\tconst cc = s.charCodeAt(this.#i);\n\t\tif (cc === 0x2d /* - */ || cc === 0x2b /* + */ || cc === 0x2e /* . */ || (cc >= 0x30 && cc <= 0x39)) {\n\t\t\t// JS-only NaN / Infinity are deliberately not accepted: a tool must not\n\t\t\t// execute with a non-finite numeric arg; they fall through #number's\n\t\t\t// NaN guard (strict throw / partial rollback) like other bad tokens.\n\t\t\treturn this.#number();\n\t\t}\n\t\treturn this.#keyword(allowBareword);\n\t}\n\n\t#object(): Record<string, unknown> {\n\t\tthis.#i++; // consume {\n\t\tconst out: Record<string, unknown> = {};\n\t\tfor (;;) {\n\t\t\tthis.#ws();\n\t\t\tif (this.#i >= this.#n) {\n\t\t\t\tif (this.#partial) return out;\n\t\t\t\tthrow new SyntaxError(\"Unterminated object\");\n\t\t\t}\n\t\t\tconst c = this.#s[this.#i];\n\t\t\tif (c === \"}\") {\n\t\t\t\tthis.#i++;\n\t\t\t\treturn out;\n\t\t\t}\n\t\t\tif (c === \",\") {\n\t\t\t\t// Tolerate leading / doubled / trailing commas.\n\t\t\t\tthis.#i++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst key = this.#key();\n\t\t\tthis.#ws();\n\t\t\tif (this.#i < this.#n && this.#s[this.#i] === \":\") {\n\t\t\t\tthis.#i++;\n\t\t\t} else if (this.#partial) {\n\t\t\t\treturn out;\n\t\t\t} else {","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/json-parse.ts#L241-L277","documentation":"Thrown by RelaxedJson.#object in strict mode when the input ends (this.#i >= this.#n) while still inside an object — the parser reached end-of-input before seeing the closing '}'. In partial (streaming) mode this is not an error; the object is auto-closed with what was parsed so far. In strict mode it throws so truncated JSON never passes as final.","triggerScenarios":"parseJsonWithRepair with a truncated object: '{\"a\": 1', '{\"a\":', or '{'. Any place end-of-input occurs inside an object body when this.#partial is false.","commonSituations":"LLM tool-call arguments cut off by a token/size limit; reading a file or network response before it fully arrived; log truncation dropping the tail of a JSON payload.","solutions":["Verify the source string is complete before parsing (check stream end, file size, response length)","For streaming/incomplete input use parseStreamingJson, which auto-closes truncated objects","Re-request or re-read the payload if it was truncated by a provider or transport","Use classifyJsonPrefix: 'prefix' means the input can still be completed, so wait for more data"],"exampleFix":"// before\nconst v = parseJsonWithRepair(`{\"path\": \"x.ts\"`); // SyntaxError\n// after: tolerate a truncated streaming buffer\nconst v = parseStreamingJson(`{\"path\": \"x.ts\"`); // {path: 'x.ts'}","handlingStrategy":"validation","validationCode":"import { classifyJsonPrefix } from \"@oh-my-pi/pi-utils/json-parse\";\n// 'complete' => safe for parseJsonWithRepair; 'prefix' => wait for more data or use parseStreamingJson\nconst state = classifyJsonPrefix(text);","typeGuard":"function isCompleteJson(text: string): boolean {\n  return classifyJsonPrefix(text) === \"complete\";\n}","tryCatchPattern":"try {\n  const value = parseJsonWithRepair<T>(text);\n} catch (err) {\n  if (err instanceof SyntaxError && err.message === \"Unterminated object\") {\n    const partial = parseStreamingJson<T>(text); // best-effort auto-closed value\n  } else throw err;\n}","preventionTips":["Never final-parse until the stream/reader signals completion","Use parseStreamingJson for incremental buffers and parseJsonWithRepair only for final parses","Verify file size / content-length against bytes actually received","Use classifyJsonPrefix to distinguish 'prefix' (wait) from 'invalid' (fail fast)"],"tags":["json","parse","unterminated","truncated"],"backgroundTag":"json-unterminated-object","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}