Skip to content

Gemini Flash's Context Window and Output Cap

7 min read · updated August 11, 2026

Gemini Flash is usually described as having a one-million-token context window. That figure is the input limit. The output cap is a separate, much smaller number, and confusing the two is the source of most “why did my answer stop” questions about the model.

The documented limits

Google publishes an input token limit and an output token limit for every model on the Gemini API models page. As listed there when this page was written, on 11 August 2026:

Model                 Input token limit   Output token limit
--------------------  ------------------  ------------------
Gemini 2.5 Flash               1,048,576              65,536
Gemini 2.0 Flash               1,048,576               8,192
Gemini 1.5 Flash               1,048,576               8,192

The input figure is 220, which is what “one million” is rounded from. The output figure moved by a factor of eight between the 2.0 and 2.5 generations, which is the single most consequential difference between them for anyone generating long documents.

These figures are read off Google’s model page and change with each model launch and occasionally between preview and general availability of the same model. Before depending on a number here, check the model page for the exact model id string you call. This page is dated for that reason.

Why there are two numbers, not one

They constrain different mechanisms, which is why they are set independently and why the ratio between them is so lopsided.

The input limit is an architectural bound: how long a sequence the model can attend over, decided at training time by the positional scheme and the attention implementation, and by what the serving hardware can hold. A million tokens of key-value cache is a large amount of memory, and the number reflects a real engineering budget.

The output limit is a serving policy. Generation is sequential — one forward pass per token — so a 65,536-token response occupies a serving slot for the duration of 65,536 sequential passes. The cap bounds how long any single request can monopolise capacity. That is why it is far below the input limit even though nothing about the architecture forbids longer output, and why it moves between model versions when serving improves rather than when the model changes.

Input and output share the window

The two limits are not entirely independent at request time. The context window holds the prompt and the generated tokens together, because each generated token is appended to the sequence and attended over on the next pass. Google documents the input limit as a limit on what you send, so in practice on Flash the arithmetic is comfortable: even a maximal 65,536-token response added to a 1,048,576-token prompt is a small fraction over, and the output cap is the binding constraint long before the sum is.

The place this matters is a long conversation. Every turn appends both your message and the model’s reply to the history, so a chat that runs for hundreds of turns grows toward the input limit from both directions. Count the assembled history with countTokens before each call rather than tracking it yourself.

What happens at each limit

  • Over the input limit. The request is rejected. You get an HTTP 400 with an INVALID_ARGUMENT status and a message naming the token count and the limit. Nothing is truncated silently and nothing is billed for the generation. This is a failure you can catch and handle.
  • At the output limit. Generation stops mid-sentence and the candidate comes back with finishReason: “MAX_TOKENS”. The partial text is returned and billed. This is not an error and will not throw in any SDK — you have to read the field. It is the same signal you get from setting maxOutputTokens too low yourself.

The asymmetry is worth restating because it catches people: exceeding the input limit is loud, and hitting the output cap is quiet. Any code that generates long output and does not inspect finishReason will eventually store a truncated document and treat it as complete.

Streaming does not help you notice. A stream that ends because the cap was reached looks exactly like a stream that ended because the model finished: the chunks stop arriving and the iterator completes. The only difference is the finishReason on the final chunk, which is the one piece of the stream most client code throws away. If you are writing generated text to storage, read the finish reason off the last chunk and refuse to persist a MAX_TOKENS result as final.

Truncation is nastiest under structured output. A response constrained to a JSON schema that hits the cap returns a document that is cut mid-token — an unterminated string, a missing closing brace — and your parser throws somewhere far from the cause. The error you see is a JSON parse failure; the error you have is an output cap. Check finishReason before parsing, not after the exception.

Thinking tokens spend the output cap

On the Gemini 2.5 models this is the surprise that costs the most debugging time. A reasoning model spends tokens thinking before it writes anything you see, and those tokens are output tokens. They are reported separately as thoughtsTokenCount in usageMetadata, but they are drawn from the same budget that maxOutputTokens bounds.

The failure mode is a response that appears empty. The candidate comes back with finishReason: MAX_TOKENS, usageMetadata shows a large thoughtsTokenCount, and there is no visible text at all — the model used the entire allowance reasoning and had nothing left to answer with. Nothing about that looks like a limit problem from the outside; it looks like the model refused.

Two fixes, and which one is right depends on the task. Raise maxOutputTokens so there is room for both phases, or lower the thinking budget so less of the allowance goes to reasoning — the budget is a separate control covered in the thinking budget parameter. Setting a tight maxOutputTokens on a reasoning model to control cost, without adjusting the thinking budget, is a reliable way to pay for tokens and receive nothing.

Reading the current figure yourself

The API will tell you, which is better than any table. The models.get method returns the limits for a model id as the service currently has them:

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash" \
  -H "x-goog-api-key: $GEMINI_API_KEY"

# -> {
#      "name": "models/gemini-2.5-flash",
#      "inputTokenLimit": 1048576,
#      "outputTokenLimit": 65536,
#      "supportedGenerationMethods": ["generateContent", "countTokens", ...],
#      ...
#    }

Reading inputTokenLimit and outputTokenLimit from models.get at start-up, and configuring your trimming logic from those values, means a model upgrade does not require you to edit a constant. It also removes the class of bug where a hard-coded 8,192 survives a migration to a model that would have allowed eight times more.

One further caution about the model id itself: an alias like gemini-2.5-flash points at whichever specific version Google currently serves under it, and that pointer moves. If your limits matter, pin the dated version string and read its limits — see what the version suffix on a Gemini model id means.