AI text tools

Why ChatGPT Returns Invalid JSON, and How to Stop It

On this page
  1. The six usual mistakes
  2. Reading the position in the error
  3. Fixing a response you already have
  4. Stopping it in your code
  5. Stopping it in your prompt
  6. A final check before you trust the data

You ask a model for JSON, it gives you something that looks like JSON, and your code throws:

SyntaxError: Unexpected token 'H', "Here is th"... is not valid JSON

or in Python:

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2

The data is usually fine. The wrapping and a few small syntax habits are not. Below are the mistakes that cause almost every failure, how to recognise each one from the error, and how to stop them happening.

The six usual mistakes

1. Text around the data

Chat models are trained to be conversational, so they often add "Here is the JSON you asked for:" before the data or "Let me know if you need changes!" after it. A parser reads the first character, finds an H instead of {, and gives up immediately. An error mentioning an unexpected letter at position 0 almost always means this.

2. Markdown code fences

In a chat interface, JSON is usually shown inside a code block. When you copy the raw response from an API, you get the fence characters too: three backticks and the word json on the first line. The error points at an unexpected backtick.

3. Trailing commas

["a", "b",] is legal in JavaScript and Python, but not in JSON. Models produce it often, especially in long lists. The error usually says something like "Unexpected token ]" or "Expecting value".

4. Single quotes and unquoted keys

{name: 'Ana'} is a valid JavaScript object and a valid Python dict, but JSON requires double quotes around every key and every string. Python's error message, "Expecting property name enclosed in double quotes", names this one directly.

5. Python and JavaScript values

True, False and None are Python. undefined, NaN and Infinity are JavaScript. JSON only knows true, false and null, and has no way to store NaN or infinity at all. These creep in when a model has just been writing code in the same conversation.

6. Output cut off part way

If a response reaches the model's output limit, it simply stops, often in the middle of a string. The error then points at the very end of the input. Depending on your browser or Node version, it reads "Unexpected end of JSON input", "Unterminated string", or "Expected ',' or '}' after property value" with a position equal to the length of the text. This is the only mistake where information is actually lost, because the model never wrote the rest.

Reading the position in the error

Most parsers tell you where they gave up, as a character position or a line and column. That position is where the parser noticed a problem, which is usually just after the real mistake. Look at the character there and the few before it:

Error mentions Likely cause
Position 0, or an unexpected letter Text before the data
An unexpected backtick Code fence
] or } right after a comma Trailing comma
"property name" or a single quote Unquoted key or single quotes
An unexpected T, F or N mid-object Python True, False or None
End of input, unterminated string, or a position at the very end Cut-off output

Fixing a response you already have

For a one-off fix, paste the response into the broken JSON fixer. It removes the surrounding text and fences, repairs the syntax, and lists every type of change it made, so you can see whether anything was guessed. For cut-off output it closes the open brackets, but you should still check the last items, because anything after the cut is missing.

Avoid fixing JSON with simple find-and-replace. Replacing every single quote with a double quote, for example, breaks any value containing an apostrophe, such as "it's". A proper repair has to understand which characters are inside strings.

Stopping it in your code

If you call a model from code, a small cleanup step before parsing handles the first two problems:

function extractJson(text) {
  const fenced = text.match(/\x60{3}(?:json)?\s*([\s\S]*?)\x60{3}/); // \x60 is a backtick
  if (fenced) text = fenced[1];
  const start = text.search(/[{[]/);
  const end = Math.max(text.lastIndexOf('}'), text.lastIndexOf(']'));
  return JSON.parse(text.slice(start, end + 1));
}

That won't fix trailing commas or Python values. For those, use a repair library such as jsonrepair (JavaScript) or json-repair (Python) as a fallback when JSON.parse fails, and log every case where it was needed, so you notice if a prompt change makes things worse.

Stopping it in your prompt

Prompt wording makes a real difference:

  • Ask for JSON only, explicitly. "Respond with only a JSON object. No explanation, no code fences." removes most of the extra text.
  • Show the exact shape. An example object with every key you expect, using double quotes and true/null, gives the model a pattern to copy.
  • Keep responses short enough. If you need hundreds of records, ask for them in batches. A cut-off response is the one failure that can't be fully repaired.
  • Ask for strings instead of special numbers. If a value can be missing, say "use null when unknown", so the model doesn't invent NaN or undefined.

The most reliable fix is to use your provider's structured output feature, often called JSON mode, structured outputs or tool calling, where you supply a schema and the API constrains the response to match it. With that in place, syntax errors become rare, though you should still check that the values make sense.

A final check before you trust the data

Valid JSON is not the same as correct data. After parsing, check that the keys you need exist, that numbers are numbers rather than strings like "12", and that lists have the length you expected. A response can be perfectly formed and still be missing half its records.

Questions people ask

Why does ChatGPT add text before the JSON?

Chat models are tuned to be conversational, so they often introduce or explain their answer. Asking for “only a JSON object, with no explanation” prevents this most of the time, and structured output modes prevent it entirely.

What does “Unexpected end of JSON input” mean?

The parser reached the end of the text while an object, array or string was still open. With AI output, it usually means the response was cut off at the model’s output limit.

Can I just use eval() to read the response?

No. eval() runs whatever code is in the text, which is a security risk with any external input. Repair the JSON instead and parse it with JSON.parse.

Is JSON with comments allowed?

Standard JSON does not allow comments. Some tools accept variants such as JSONC or JSON5, but most parsers and APIs reject them.