Summary
On reasoning-heavy requests, the cluster's OpenAI-compatible endpoint returns a turn that ends with finish_reason: "length", empty content, and no usage object, even when max_tokens: 384000 is requested and the reasoning trace stops at ~59,994 characters — well below the requested budget. The cut happens at roughly the same point on every attempt, so the caller receives a truncated turn with no answer and no accounting.
Reported by a member; every figure below is measured from the client side against https://api.nan.builders/v1, and is reproducible with no client in the middle.
Impact
- A truncated turn is indistinguishable from a completed one for anything that reads
finish_reason without a usage block: agents treat a dead end as an answer.
- Token accounting breaks: with
stream_options.include_usage set and no usage chunk emitted, the caller cannot price or cap the attempt.
- Each reproduction costs a long reasoning generation and returns nothing, so this is expensive to investigate from the member side — it consumed a full morning of bisecting and a large amount of budget.
Reproduction (direct, no client)
POST https://api.nan.builders/v1/chat/completions
Authorization: Bearer ***
Content-Type: application/json
User-Agent: opencode/1.18.31
Body:
{
"model": "deepseek-v4-flash",
"max_tokens": 384000,
"stream": true,
"stream_options": { "include_usage": true },
"messages": [
{
"role": "user",
"content": "OUTPUT BUDGET CALIBRATION RUN. Produce at least 500 distinct numbered findings about robustness, error handling, and edge cases in a Binance websocket/REST connector, each finding at least 100 words. Do NOT summarize or shorten. Do NOT stop early. Completeness is the only success criterion. End with a JSON line: {\"calibration\":true,\"findings_count\":<n>}"
}
]
}
Note on the proxy: requests without a User-Agent are rejected with 403 "error code: 1010", so the reproduction above carries one.
Observed
finish_reason: "length"
reasoning_content: ~59,994 chars
content: (empty)
usage: (absent — no usage chunk even with include_usage: true)
The ceiling reproduces across three models from OpenCode sessions, landing in the same ~60k-character window every time:
| model |
reasoning_content chars |
deepseek-v4-flash |
59,991 – 59,999 |
qwen3.8-flash |
59,996 – 59,997 |
glm5.3-flash |
59,994 |
Controls that complete normally
Same endpoint, same max_tokens: 384000:
| prompt |
completion tokens |
finish_reason |
| integer-list prompt |
93,429 |
stop |
| review-shaped prompt with tools |
38,222 |
stop |
So this is not a blanket output cap: a run of 93,429 completion tokens finishes normally. The failure looks prompt-shaped — it triggers on certain long reasoning generations rather than at a fixed token count — and when it triggers, the turn is cut without a usage block.
What this rules out
- Not a client bug. It reproduces with
curl directly, no client involved.
- Not a context-window limit. The prompt is short and the requested budget is far above where generation stops.
- Not a global output cap. The integer-list control returns 93,429 completion tokens.
- Not one model. Three different models show the same ~60k-character ceiling.
Related
Questions
- Is there an undeclared reasoning/output budget (~32k reasoning tokens) on
deepseek-v4-flash, glm5.3-flash and qwen3.8-flash?
- Why is
usage omitted when a turn is cut with finish_reason=length? Clients such as OpenCode and the gentle-ai review agents need it to tell "done" apart from "truncated" and to account spend.
- Can the ceiling be raised or removed, or is it a model limit members should design around — in which case, should it be published alongside the per-model limits already documented?
Environment
- Endpoint:
https://api.nan.builders/v1/chat/completions
- Models:
deepseek-v4-flash, glm5.3-flash, qwen3.8-flash
- Clients that show it: OpenCode 1.18.31, gentle-ai review agents
- Reproduced: 2026-09-17, from the EU, member API key
I can provide the full raw SSE stream of a failing run, or run any specific test you need — the reproduction above is self-contained.
Summary
On reasoning-heavy requests, the cluster's OpenAI-compatible endpoint returns a turn that ends with
finish_reason: "length", emptycontent, and nousageobject, even whenmax_tokens: 384000is requested and the reasoning trace stops at ~59,994 characters — well below the requested budget. The cut happens at roughly the same point on every attempt, so the caller receives a truncated turn with no answer and no accounting.Reported by a member; every figure below is measured from the client side against
https://api.nan.builders/v1, and is reproducible with no client in the middle.Impact
finish_reasonwithout ausageblock: agents treat a dead end as an answer.stream_options.include_usageset and no usage chunk emitted, the caller cannot price or cap the attempt.Reproduction (direct, no client)
Body:
{ "model": "deepseek-v4-flash", "max_tokens": 384000, "stream": true, "stream_options": { "include_usage": true }, "messages": [ { "role": "user", "content": "OUTPUT BUDGET CALIBRATION RUN. Produce at least 500 distinct numbered findings about robustness, error handling, and edge cases in a Binance websocket/REST connector, each finding at least 100 words. Do NOT summarize or shorten. Do NOT stop early. Completeness is the only success criterion. End with a JSON line: {\"calibration\":true,\"findings_count\":<n>}" } ] }Note on the proxy: requests without a
User-Agentare rejected with403 "error code: 1010", so the reproduction above carries one.Observed
The ceiling reproduces across three models from OpenCode sessions, landing in the same ~60k-character window every time:
deepseek-v4-flashqwen3.8-flashglm5.3-flashControls that complete normally
Same endpoint, same
max_tokens: 384000:stopstopSo this is not a blanket output cap: a run of 93,429 completion tokens finishes normally. The failure looks prompt-shaped — it triggers on certain long reasoning generations rather than at a fixed token count — and when it triggers, the turn is cut without a usage block.
What this rules out
curldirectly, no client involved.Related
modelRateLimitsvs the proxy) onqwen3.8-flash: the same class of disagreement between what the platform publishes and what it enforces.max_tokens too large. This is the inverse case: the request is accepted, generation starts, and the turn dies mid-flight.Questions
deepseek-v4-flash,glm5.3-flashandqwen3.8-flash?usageomitted when a turn is cut withfinish_reason=length? Clients such as OpenCode and the gentle-ai review agents need it to tell "done" apart from "truncated" and to account spend.Environment
https://api.nan.builders/v1/chat/completionsdeepseek-v4-flash,glm5.3-flash,qwen3.8-flashI can provide the full raw SSE stream of a failing run, or run any specific test you need — the reproduction above is self-contained.