Home › Guides › "Unexpected end of JSON input" — what it means and how to fix it
"Unexpected end of JSON input" — what it means and how to fix it
Direct answer: the JSON text ended before the document finished — something was cut off in transit: an LLM response stopped at its token limit, a request timed out, or a file/download was truncated. The parser is not complaining about a typo; it ran out of input. You cannot reconstruct the missing bytes, but you can recover everything that arrived complete with the tool below.
Recover the complete prefix of your cut-off JSON
Recovery never invents data: whatever was cut off is dropped and listed, open structures are closed, and any value that had to be force-closed is flagged as suspect. Processed locally — nothing is uploaded.
Recovered JSON
Recovery Note — exactly what was cut, closed, or dropped
Why this error happens
JSON.parse (and every strict parser) reads a document as a structure that must close: every { needs its }, every string its closing quote. "Unexpected end of JSON input" is the parser arriving at the final byte with the structure still open. The usual sources:
- LLM output limits. The LLM was still writing when the token budget ran out — the most common cause today, especially with long structured responses.
- Network cuts. A fetch that timed out, a connection reset mid-body, or a proxy that truncated a large response. Code that parses
response.text()without checking completeness inherits the cut. - Files and logs. A process killed while writing, a disk that filled, a log rotation that sliced a line, a copy that was interrupted.
- String limits in pipelines. A field, buffer, or tool in the chain (spreadsheets and some automation platforms are frequent offenders) silently capping the payload length.
Your three options
| Option | When it is right |
|---|---|
| Re-fetch / re-generate | The source is reachable and cheap to ask again — with a bigger token limit, pagination, or a longer timeout. Always best when available: you get the real data, not a prefix of it. |
| Recover the prefix (the tool above) | The source is gone, expensive, or non-deterministic (an LLM will not repeat itself). You keep every complete record and lose only the incomplete tail — with a note of exactly what was dropped. |
| Fail loudly | The data is financial, medical, or otherwise unsafe to use partially. A prefix is a partial truth; sometimes the correct engineering answer is an error and an alert. |
What recovery does — and refuses to do
The recovery scan tracks the open structure and the last complete boundary. The incomplete trailing token is discarded — a number like 12 at the cut could be the start of 1234, so keeping it would be a guess wearing a fact's clothes. If the cut fell mid-pair, the pair goes with it. Open arrays and objects are then closed in stack order. One flagged exception: a string value that lost only its closing quote is closed and explicitly marked suspect in the Recovery Note, because its content may be cut too. The result is valid JSON that is a true subset of what was sent — every value in it was fully present in your input.
If instead your JSON is complete but messy — quotes, commas, comments — that is a different problem: use JSON Repair, which fixes syntax and lists every change.
Frequently asked questions
What does "Unexpected end of JSON input" mean?
Your parser reached the end of the text while the JSON document was still unfinished — an object, array, string, or value was left open. The data was cut off somewhere between its source and your code: an LLM response that hit its token limit, a timed-out fetch, a truncated file or log line.
Can the missing part be reconstructed?
No — and be wary of anything that claims otherwise. The bytes after the cut do not exist in your input, so completing them means inventing data. What can be recovered honestly is the largest complete prefix: everything that arrived intact, closed into valid JSON, with the incomplete tail dropped and listed.
How do I stop it happening?
At the source: raise the output token limit (or stream and concatenate) for LLM calls; add timeouts and retries with backoff for fetches; check Content-Length against bytes received for downloads; and paginate large API responses instead of requesting one giant document.