How to fix: model returned invalid / unparseable JSON
Last verified: June 2026· Extraction and tool-use pipelines
Where this shows up
Extraction and tool-use pipelines
How it shows up
The same root cause surfaces in a few different ways. If any of these match, you're in the right place.
- A parse error on output that looks correct at a glance but carries a prose preamble such as "Here is the JSON you asked for".
- Valid JSON that fails schema validation because a field is missing, renamed, or returned as a string where a number was expected.
- Output wrapped in a markdown code fence, so the first character the parser sees is a backtick.
- Intermittent failures on long responses, where the JSON is well formed up to the point it was cut off.
Diagnose it first
Confirm which cause you actually have before changing anything — most wasted time here comes from fixing the wrong one.
| Check | What the result tells you |
|---|---|
| Log the raw completion string before any parsing. | The failure mode is visible immediately and they are very different problems: a preamble is a prompting issue, a truncated object is a token-limit issue, a wrong type is a schema issue. |
| Read the finish reason on the response. | If it indicates the token limit was reached, the JSON is not invalid so much as incomplete, and no amount of prompt tightening will fix it. Raise max_tokens or reduce what you asked for. |
| Check whether you are using the provider's structured-output or JSON mode at all. | Asking for JSON in the prompt is a request; constrained decoding is a guarantee. Many teams discover they were only ever asking. |
| Validate against the schema separately from parsing. | Syntactically valid JSON with the wrong shape is a different bug from malformed JSON, and conflating them in one try/except hides which one you have. |
The fix
- 1Use structured outputs (schema-enforced JSON) if your provider/model supports it — this guarantees parseable output at generation time.
- 2For tools, enable strict tool use so arguments validate against your schema.
- 3Stop prefilling the assistant turn to force JSON — modern models reject prefills; use the schema parameter instead.
- 4Always parse with a real JSON parser and handle failure by retrying with a clarifying instruction, not by string-patching the output.
- 5Validate the parsed object against your schema and surface mismatches as errors the model can correct.
Provider-specific behaviour
The error means roughly the same thing everywhere, but each provider signals it differently.
- Structured output versus JSON mode
- These are not the same guarantee. A basic JSON mode typically promises syntactically valid JSON and nothing about the fields; a schema-constrained mode enforces the shape during decoding. Check which one the endpoint you are calling actually provides.
- Schema complexity
- Deeply nested schemas, unions and open-ended maps are handled less reliably than flat objects with explicit fields, and some providers reject constructs their constrained decoder cannot express. Flattening the schema is often faster than fighting it.
What doesn't work
Common fixes for this error that look right and aren't.
Stripping markdown fences with a regular expression and moving on.
It works until the model returns a fence inside a string value, and it leaves the underlying cause — that you are asking rather than constraining — in place. Use the provider's structured output mode instead.
Adding 'ONLY return valid JSON' in capitals to the prompt.
Emphasis reduces the frequency of preambles without eliminating them, so you end up with a rare failure that surfaces in production rather than in testing. A constrained decoder removes the class of failure.
Retrying the same request on a parse failure.
With unchanged input and a stable model this often produces the same shape of output, and it doubles the cost. Feed the parse error back as a repair turn, or fix the constraint.
Prevent it
Adopt structured outputs everywhere you consume model output programmatically, and cover the route with an eval so regressions are caught.
Common variations and related errors
You'll usually hit this same root cause under a few different names. Same fix.
- "Invalid JSON"
- "JSON parse error"
- "expected property name"
- "model returned malformed JSON"
- "function call arguments invalid"
- openai.InvalidJSONOutput
- "tool_use_failed"
Code: drop-in retry helper
A minimal typescript helper that handles the most common version of this error. Copy, paste, adjust the policy to your traffic.
// Always request structured outputs (schema-enforced) for JSON routes.
// If you can't, retry with a clarifying instruction and surface the error.
import OpenAI from 'openai';
const client = new OpenAI();
async function extractOrder(text: string) {
const schema = {
type: 'object',
properties: { orderId: { type: 'string' }, total: { type: 'number' } },
required: ['orderId', 'total'],
additionalProperties: false,
} as const;
const res = await client.responses.create({
model: 'gpt-4o-mini',
input: text,
text: { format: { type: 'json_schema', name: 'order', schema, strict: true } },
});
return JSON.parse(res.output_text);
}Frequently asked questions
What causes “model returned invalid / unparseable JSON”?
The model produced free-form text or slightly malformed JSON instead of strictly valid, schema-conforming output.
How do I prevent “model returned invalid / unparseable JSON” from recurring?
Adopt structured outputs everywhere you consume model output programmatically, and cover the route with an eval so regressions are caught.
Why does the model add text around the JSON?
Because a plain prompt asking for JSON is a request rather than a constraint, and conversational preamble is the model's default behaviour. The durable fix is the provider's structured-output or JSON mode, which constrains decoding so non-JSON tokens cannot be emitted. Prompt emphasis reduces the rate but leaves a low-frequency failure that will surface in production rather than in testing.
The JSON parses but the fields are wrong. Is that the same bug?
No, and it is worth handling separately. Syntactic validity and schema conformance are different guarantees, and a basic JSON mode typically provides only the first. Validate against an explicit schema after parsing, and prefer a schema-constrained mode where the provider offers one. Flat schemas with explicit fields are handled far more reliably than deeply nested or open-ended ones.
How should I handle a genuine parse failure in production?
Validate, then repair, then fail cleanly. Send the invalid output back with the specific parse or validation error and ask for a correction, which succeeds far more often than a blind retry of the original request. Cap repairs at one or two attempts, and make sure the failure path is a handled outcome rather than an exception reaching the user. Log the raw string either way — it is the only way to tell the failure modes apart later.