maxTokens (4096) is too close to contextLength (4096)
No request was sent. This message is produced by the client before anything leaves your machine: it compared two numbers from its own configuration and concluded that a request built from them could not succeed. That rules out everything people check first — your API key was not consulted, your quota was not touched, the provider was not asked for an opinion, and the model’s real limits played no part in the arithmetic. Both numbers in the message came from your side, and at least one of them is usually wrong.
Data as of 2026-09. Vendor limits and defaults change; check the official docs for current values before acting on any number below.
Two budgets, one window
A context window is a single pool that has to hold the conversation you send
and the reply you get back. contextLength is the client’s belief about the
size of that pool. maxTokens is how much of it you have reserved for output
before a single input token is counted.
Subtract the second from the first and you have your actual input budget. When the two are equal, that budget is zero: there is no arrangement of prompt, system message and tool definitions that fits, including the empty one. The client can prove the request is impossible without sending it, so it stops.
That is a better error than the one it replaced. The server-side version of
the same squeeze arrives after the round trip, as a 400 that counts your tokens
and tells you the total — which costs you latency and, on OpenAI, rate limit. The
documented behaviour there is that your rate limit is calculated as the maximum
of max_tokens and the estimated tokens of the request, so an inflated output
reservation draws down your per-minute token allowance whether or not the model
ever produces that much. A local guard costs you nothing.
Why the two numbers being identical is the real clue
4096 and 4096 is not a coincidence, and it is rarely a value anybody chose on
purpose for both fields.
When a client cannot identify the model you named, it falls back to conservative
defaults rather than refusing to start. If the same round number appears on both
sides of the message, the leading hypothesis is that the client never learned
anything about your model and is reporting its own fallback back to you. The
model you are actually calling may have a window orders of magnitude larger —
the current featured OpenAI models publish a context window of 1,050,000 tokens,
with a maximum input of 922,000 tokens and a maximum output of 128,000 tokens.
Lowering maxTokens to satisfy the guard in that situation “fixes” the error and
leaves you running a large-context model inside a tiny pretend window, wondering
later why the tool keeps truncating.
So the first question is not “what should I set maxTokens to”. It is “does
this tool know what model it is talking to?” The three situations that produce
an unrecognized model are all common: a model name the client’s catalog does not
carry yet, a custom or self-hosted endpoint behind an OpenAI-compatible URL, and
a gateway that renames models on the way through. In all three the client has no
way to discover the limits, so it guesses, and its guess is deliberately small.
Telling the two situations apart
Both numbers are the same round default, and you did not set either. The client is guessing. Configure the real context length explicitly and the guard stops firing for the right reason. Check the provider’s documentation for the model’s current window rather than copying a number from a forum thread; windows change with every model generation and a stale number reintroduces this problem from the other direction.
You set contextLength yourself and it matches the model’s documented
window. Then the guess is not the problem and your output reservation genuinely
is too large. This is the honest version of the error and the fix is to decide
how long a reply you actually need.
The numbers differ but the message still fires. The guard is not testing for equality — it is testing whether the gap left for input is big enough to be useful. A reservation that consumes nearly the whole window fails the same check. Read the gap, not the difference between the labels.
It appeared after you pointed the tool at a proxy or a different endpoint. Suspect the model identifier the proxy exposes. The client is matching on a name, and a renamed model is an unknown model.
Is retrying useful?
No. Nothing was sent, so there is nothing to send again.
This is a pure function of two configuration values. Re-running the same command
re-reads the same config and performs the same subtraction, with the same result,
for as long as the values are unchanged. There is no server to be busy, no
retry-after to honor, and no documented base delay to copy, so any wait you
insert is a number you invented.
The useful consequence is diagnostic. Because the check is local and deterministic, a change either clears the message on the very next run or does not — you never have to wonder whether you fixed it or got lucky. If you edited a config file and the message is identical, the file you edited is not the file the tool is reading, and that is now the thing to investigate.
Fix by scenario
- Client fell back to defaults — set the context length explicitly to the
model’s documented window, then set
maxTokensto the output you need. Do these in that order; setting the second first is how people end up with a working tool and a wrong window. - Custom or compatible endpoint — state both values in the configuration. The client cannot discover them and will not ask.
- Genuinely oversized output reservation — size
maxTokensto the longest reply you actually want, not to the largest number the model will accept. Reserving output you never use is not free: it shrinks your input budget on every request, and on OpenAI it also counts toward the per-minute token limit. - You need both a long input and a long output — that is a model choice, not a config tweak. Note that maximum output is published separately from the context window and is much smaller than it, so “the window is huge, therefore I can reserve half of it for output” does not follow.
- Config edits have no effect — find which configuration file the tool actually loaded. Precedence between a global config, a project config and a command-line override decides this, and a value you can see is not necessarily a value in effect.
How to confirm it’s fixed
Do the arithmetic before you run anything. contextLength − maxTokens is your
input budget; write that number down and compare it against the size of a real
request — your system prompt, your tool definitions, the files you attach, and a
representative conversation. If the budget is not comfortably larger than your
typical input, you have moved the failure rather than fixed it, and it will
come back as a server-side overflow later.
Then test with your largest realistic prompt, not with “hello”. A short prompt succeeds under almost any configuration and proves nothing about the boundary you just moved. The confirmation you want is the big case passing, twice, with the values you set visible in the tool’s own reporting rather than in the file you edited.
Related errors
- openai.BadRequestError: this model’s maximum context length is … is the same squeeze judged by the server instead of your client: it fires after the request, counts your real tokens, and tells you both numbers. Read it if your configuration is already correct and you are still overflowing.
- stream disconnected before completion: your input exceeds the context window is the overflow arriving mid-stream, where it reaches you as an event rather than a clean refusal.
- Error running remote compact task: stream disconnected before completion is what happens when the automatic summarization meant to keep you under the limit is itself what fails.
- The context window calculator does exactly the subtraction this page asks for: what fits, for which model, with how much left for the reply.