Four thousand and ninety three of four thousand and ninety six output tokens went to reasoning. The visible reply was an empty string. That happened four times in a row, at 407.8, 369.0, 383.4 and 362.1 seconds, on a model that answers a simple question in under three seconds.
Nothing had crashed. An LM Studio empty response looks like this from the outside: HTTP 200 every time, a well formed response object, a token count, and no content in it.
The answer turned out to be 178 tokens away. Not a broken model, not a bad prompt, not a wrong parameter. The cap was 4,096 and the model needed 4,274, and every one of those seven minute failures was a request that stopped just short of the finish line. Getting there took most of an afternoon and one badly wrong theory, so here is the short version. The input was a single frame from ARC-AGI-3, which runs locally on an ordinary Mac, but nothing here is specific to that benchmark. Any reasoning model, any large input, same trap.
What an LM Studio empty response actually means
The response body tells you exactly what happened if you read past choices[0].message.content. This is LM Studio’s OpenAI compatible endpoint, so the shape is the one you already know. Two fields matter.
finish_reason was length, not stop. The model did not decide it was done, it was cut off. And usage.completion_tokens_details.reasoning_tokens was 4,093 out of 4,096 total output tokens.
Reasoning tokens are output tokens. OpenRouter’s documentation states it plainly: “Reasoning tokens are counted as output tokens for billing purposes”, and for Anthropic models, “max_tokens must be strictly higher than the reasoning budget to ensure there are tokens available for the final response after thinking.” The same arithmetic applies locally. Your cap is one shared pot, and the thinking drinks from it first.
This is a known shape of bug across providers, not something peculiar to LM Studio. An open issue on Google’s Python SDK describes it precisely: a MAX_TOKENS finish reason “appears to be given if thoughts_token_count + output_token_count > max_output_tokens“, and when it fires, “the response text is empty”, which the reporter notes makes debugging very difficult.
So the first read is easy. The model thought until it ran out of room, and there was nothing left to say the answer with. The fix is equally obvious: give it more room.
It is the right fix. It is also the one that took four failed attempts and most of an afternoon, because the numbers it produces along the way argue convincingly that it is the wrong one.
How big does max_tokens need to be for a reasoning model
The obvious move is to raise the cap, so the cap went from 16 to 256 to 1,024 to 4,096. At 16, thirteen tokens went to reasoning and the reply was empty. At 1,024, one thousand and twenty one, empty. At 4,096, four thousand and ninety three, empty. Three other changes were tried at that same 4,096 ceiling, on the same input, in the same session:
| What was changed | Time | Reasoning tokens | Answer |
|---|---|---|---|
| Nothing, 4,096 cap | 407.8s | 4,093 | none |
| JSON schema forcing one of four action names | 369.0s | 4,093 | none |
| Prompt compressed from 4,191 to 1,522 tokens | 383.4s | 4,093 | none |
reasoning_effort set to low | 362.1s | 4,093 | none |
At this point the pattern looks damning. Every reasoning count is the cap minus three. A model that needed a fixed amount of thought would terminate cleanly somewhere and leave the rest unused, and this one never does, so the reading writes itself: the thinking is not converging, and no cap will ever be big enough.
That reading is wrong, and it is worth showing rather than quietly deleting, because it is the trap.
Raising the ceiling to 16,384 produced this, on the same raw 64×64 board:
442.7s finish=stop in=4179 out=4281 reasoning=4274 content='ACTION1'It converged. It always would have. The model wanted 4,274 reasoning tokens and the cap was 4,096, so it was cut off 178 tokens short, four separate times, at roughly six and a half minutes each. The cap minus three pattern was never evidence of a runaway. It is just what truncation reports: when the limit fires, the reasoning count equals the limit, whatever the limit is. Reading it as a diagnostic is reading the ruler instead of the thing being measured.
So the schema did not fail, and low effort did not fail, and compression did not fail. All three were run under a ceiling that was 4% too low, which is the only variable that mattered.
How to tell a stuck local model from a slow one
Before rewriting a prompt, find out whether the model is broken, the server is broken, or the input is simply expensive. Four calls settle it, and three come back in under thirty seconds.
Start trivial and work up. On gemma-4-31b-qat through LM Studio, on a studio test stack with 48 GB of unified memory:
"Reply with exactly: ACTION1" -> 2.8s, 25 reasoning tokens, answered
"What is 2+2? Number only." -> 4.5s, 44 reasoning tokens, answered
An 8x8 grid, pick one action -> 25.8s, 305 reasoning tokens, answered
A 64x64 grid, cap 4,096 -> 407.8s, 4,093, cut off, empty
A 64x64 grid, cap 16,384 -> 442.7s, 4,274 reasoning tokens, answeredThat ladder is the whole diagnostic. The server is healthy, the model loads, the chat template works, and the model is willing to answer a grid question. What changes across those five rows is only how much thinking the input demands, and the last two rows differ by nothing except how much room it was given to do it in.
The rule that falls out: never debug a reasoning model against a cap you have not first proved is generous. Set it absurdly high, find out what the task actually costs, then set the real limit above that number. We use the same escalation habit when measuring what a local agent’s context really costs, for the same reason: you cannot tune a variable you have accidentally pinned.
How reasoning tokens scale with what you show the model
Once the ceiling stops interfering, the real behaviour is visible. The same game frame was sent five ways, changing only how the board was described, with everything else held constant: same model, same machine, same system prompt, same four legal actions. The model is gemma-4-31b-qat, the one we ran against Qwen 3.5 earlier this year.
| Board as sent | Input tokens | Reasoning tokens | Time | Answer |
|---|---|---|---|---|
| Downsampled to 8×8 | 147 | 692 | 66.9s | ACTION1 |
| Colour summary only | 287 | 990 | 89.2s | ACTION1 |
| Downsampled to 16×16 | 343 | 2,136 | 191.9s | ACTION1 |
| Downsampled to 32×32 | 1,127 | 2,673 | 249.3s | ACTION2 |
| Full 64×64, raw hex | 4,179 | 4,274 | 442.7s | ACTION1 |

Reasoning tokens spent on one ARC-AGI-3 frame at four resolutions, tested on a 48 GB M4 Pro, 4 September 2026. Every bar is a completed run: the full board needed 4,274 tokens of thought.
Sixty four cells cost 692 tokens of thought. Four thousand and ninety six cells cost 4,274. The board grew by 64 times and the thinking grew by about six, so it is sublinear, but it is relentless, and it is what sets the floor under your cap.
Now compare the fourth row with the third from the earlier table. The 32×32 board arrives as 1,127 input tokens and needs 2,673 tokens of thought. The 64×64 board compressed with run length encoding arrives as 1,522 input tokens, barely a third larger, and needs 4,274. Compressing the text changed the prompt size and did not change the work, because the board underneath was still 64 by 64.
That is the useful shape of it. The model reasons over the cells you describe, not the tokens you spend describing them. Shrinking the description buys you context, not thinking time, and if your problem is an empty response then thinking time is the only thing you needed.
When to downsample instead of raising the cap
Raising the ceiling works. It also costs 442.7 seconds a call at full resolution, and the machine can do nothing else while it runs.
Downsampling the same frame to 16×16, taking the most common colour in each 4 by 4 block, produces an answer in 191.9 seconds. Same model, same question, same board, and 2.3 times faster for a representation that keeps four times the spatial detail of an 8×8. A colour summary is cheaper still: one line per colour with its cell count and bounding box, four lines of numpy, 287 input tokens, an answer in 89.2 seconds. No grid at all.
So the decision is not accuracy against speed, it is how much of the board the task actually needs. Ask for a full 64×64 read when a coarse one would do and you are paying five times the wall clock for detail the model may not use.
Then the part worth being blunt about. A first time human clears level 1 of this game in 22 moves. At 191.9 seconds a move, matching that human on one level out of seven is seventy minutes of a machine that can do nothing else, with no reason to think those 22 moves would be the right ones.
Which is why the teams that won money on this benchmark, running this exact model class locally, never asked for a keystroke. One gives its model a Python console and has it turn the board into variables and write code that plays. Another renders frames as labelled images and takes back a single JSON object. Both moved the per move decision out of the model. The model writes the player, and the player plays.
That is a different build from a prompt change, and it is the same lesson as what a coding agent’s system prompt really costs: on local hardware, optimise how little you ask the model to do per call.
The lesson that cost the most to learn is the cheapest to pass on. An empty response with finish_reason: length tells you nothing about whether the model can do the job, because a truncated reasoning count always equals your own limit and always looks like a runaway. Raise the cap far past anything reasonable, once, and read what the task really costs. Only then decide whether to pay it or shrink the question.
