Notes · Sep 6, 2026

# JSON from a model: the fence, the sentence after it, and the cut at max_tokens

Ask a model for JSON and you get JSON — wrapped in a sentence, a code fence and a closing pleasantry. The parser stops on the first letter.

A model’s reply, unwrapped — A reply pasted whole — a sentence, a ```json fence, a sentence: one fix unwraps the block and says what it dropped; Fix all applies it and ⌘Z puts the reply back. · 8 s

## What the reply actually is

A reply is three things: a sentence, a fenced block, a sentence. The block is the document. JSON.parse on the whole reply says “Unexpected token 'H', "Here is th"... is not valid JSON” — it read the first letter of the first sentence and gave up, which is right, and tells you nothing about the JSON. Prompting for “JSON only” helps until it does not: a model that was told to answer with JSON still opens a fence about a third of the time, adds a language tag to it, or closes with a line of thanks.

The fence is not noise. It is the model’s own marker of where the document starts and ends, and the one thing in the reply a reader can trust.

```
Here is the corrected configuration:

```json
{
  "model": "gpt-4.1-mini",
  "temperature": 0.2,
  "tools": ["search", "calculator"],
  "max_tokens": 4096,
  "stop": ["\n\n"]
}
```

…
```

## One fix, not a regex

Pasted whole, the reply above needs 1 fix — “Unwrap the ```json fence · 2 lines of text around it dropped”. The block inside the fence becomes the document byte for byte; the fence lines and the two sentences go, and the fix says how many lines it dropped. Undo puts the reply back exactly as the model wrote it.

A regex that strips ``` does the first part. It does not say what it removed, it keeps the sentence before the fence, and it has nothing to say when the fence is the only thing that went wrong — which it usually is not.

## The cut at max_tokens

The other way a reply breaks is at the token limit: the fence opens, the document starts, and the text stops mid-word. The sample below needs 2 fixes — “Unwrap the ```json fence that never closes” and “Complete the cut tail with null · close 3 containers”. The open list and the open object are closed in order; the key the cut left half-written stays half-written, with null after it, so nothing is invented and the tree shows exactly where the model ran out.

What the page will not do is finish the thought. A cut is a cut; the fix makes the rest parse and marks where it ends.

```
```json
{
  "summary": "Three orders shipped late this week",
  "orders": [
    {"id": "ord_1", "days_late": 2},
    {"id": "ord_2", "days_late": 5},
    {"id": "ord_3", "days_l
```

## Upstream

Where the API offers a JSON mode or a response schema, use it: the fence goes away at the source, and a cut becomes an error you can retry rather than a document you have to close. Where it does not, keep the reply’s bytes — the fence and the sentences are the evidence of what the model did — and let the fix name what it dropped. That is what the fix page does, on the page, with nothing uploaded.

## Try it

## Try it on the file that broke your afternoon.

free while in alpha · no signup

---

Canonical: https://unstringify.com/notes/llm-json-in-a-code-fence
