How to Recover JSON That an LLM Cut Off at max_tokens
When ChatGPT, Claude or Gemini hit the token limit, the JSON stops mid-string. How to recover the complete part with the repair tool, how to tell what was lost, and how to stop it happening.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →You asked a model for a long JSON list and the answer simply stops:
"description": "Electric lift, memory presets, and a cable tray under the
No closing quote, no }, no ]. JSON.parse throws Unexpected end of JSON input; Python says Unterminated string starting at…. The model hit its output limit (max_tokens, max_output_tokens) in the middle of a value. This guide shows how to keep everything that did arrive, how to see exactly what was lost, and how to prevent it.
First: confirm it was the token limit
Every major API tells you why the output stopped:
| API | Field | Value when cut off |
|---|---|---|
| OpenAI Chat Completions | choices[0].finish_reason | "length" |
| OpenAI Responses | status / incomplete_details.reason | "incomplete" / "max_output_tokens" |
| Anthropic Messages | stop_reason | "max_tokens" |
| Gemini | candidates[0].finishReason | "MAX_TOKENS" |
If the reason is the limit, the JSON is not "malformed" — it is unfinished. Repairing it gives you the complete records; it cannot give you the missing ones.
Step by step
- Paste the whole response into the repair tool, including the ```
`json``` fence if there is one. The fence is stripped for you. - Tap Fix My JSON. The tool closes the open string, then every open object and array, in the right order.
- Read the report. The truncation is named as its own line (structures that were closed at the end). That line is your signal that data is missing.
- Open Diff View. Everything before the cut is unchanged; the only additions are the closing characters at the very end.
- Decide what to do with the last record. It is syntactically complete now but its last value is cut (
"…a cable tray under the"). Drop it, or re-request it.
Keep only complete records
In code, after repairing, the safest move is to drop the last element of the list that was being written when the output stopped:
import json
data = json.loads(repaired_text)
products = data["products"]
if finish_reason == "length":
products = products[:-1] # the last one was being written when the limit hit
Stop it happening
- Raise the limit for list-shaped answers, or ask for fewer items per call and page through them.
- Ask for JSON Lines (one object per line) for long lists: a cut then loses one line, not the whole document — see turning NDJSON into an array.
- Use structured outputs where the API offers them; the limit can still cut the output, but the shape of everything before it is guaranteed — see OpenAI JSON mode vs structured outputs.
- Check the stop reason in code and retry before you parse.
Limitations
- Missing data stays missing. The tool closes structures; it never invents values, keys or records.
- A cut inside a number or keyword (
"price": 34,"in_stock": tr) can only be closed in a guessed form; whatever the report shows, treat the last record as unreliable. - Prose around the JSON. A sentence before the fence ("Sure! Here is the JSON:") is removed with the fence; check the report to confirm it was treated as prose.
- Prose and other code blocks. If the reply has several fenced blocks, the first one that looks like JSON is used.
Related
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles