Skip to content

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 maxTokens to 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 maxTokens to 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.