OpenAI context_length_exceeded: Fix the Maximum Context Length Error

Quick Fix

Hitting This model's maximum context length is N tokens? The fix is to fit input + requested output under the window:

  • Count tokens before you send and trim the largest input — usually conversation history or a giant RAG chunk. Use the token counter.
  • Lower max_tokens — it’s reserved up front and counts against the window, so an oversized value alone can trigger this.
  • If the input is genuinely large, switch to a bigger-context model or chunk it (map-reduce) instead of sending it all at once.

context_length_exceeded means the total size of your request — input tokens plus the output tokens you reserved with max_tokens — is larger than the model’s context window. Unlike a 429, this isn’t about rate; it’s about a single request being too big. It arrives as an HTTP 400, so retrying it unchanged fails every time. You fix it by making the request smaller.

What this error means

The body names the limit and how far over you went:

context_length_exceeded 400
{
"error": {
  "message": "This model's maximum context length is 128000 tokens. However, your messages resulted in 129500 tokens (124500 in the messages, 5000 in the completion). Please reduce the length of the messages or completion.",
  "type": "invalid_request_error",
  "param": "messages",
  "code": "context_length_exceeded"
}
}

The key idea most people miss: the context window is shared between input and output. If a model has a 128K window and you send 126K tokens of input, you can only ask for ~2K output tokens. Set max_tokens to 8K and you’ll overflow even though the input alone fit.

The window holds input + output together (illustrative).
Model context windowYour input tokensmax_tokens you reservedResult
128,000 124,5005,000❌ 129,500 > 128,000
128,000 124,5002,000✅ fits
128,000 60,00016,000✅ fits

Common causes

  • Runaway conversation history. A chat app that appends every turn grows unbounded; eventually the full transcript blows the window. The single most common cause in production.
  • Oversized RAG context. Retrieving too many or too-large chunks and stuffing them all into the prompt.
  • Large documents pasted whole. Summarizing or analyzing a long PDF/codebase in one call.
  • max_tokens set too high. The completion reservation is counted against the window before generation starts. A big default (e.g. 16K) eats space the input needed.
  • Wrong model assumption. Targeting a model with a smaller window than you thought. Check the real number with the context-window checker.

How to fix it

Count tokens before you send

Stop guessing. Measure input size and leave headroom for the output:

Python — count tokens and guard the window
import tiktoken

def num_tokens(messages, model="gpt-4o-mini"):
  enc = tiktoken.encoding_for_model(model)
  # ~4 tokens of overhead per message for role/formatting metadata.
  total = sum(len(enc.encode(m["content"])) + 4 for m in messages)
  return total + 2  # priming tokens

CONTEXT_WINDOW = 128_000
RESERVE_FOR_OUTPUT = 2_000

msgs = [{"role": "user", "content": "..."}]
budget = CONTEXT_WINDOW - RESERVE_FOR_OUTPUT
if num_tokens(msgs) > budget:
  raise ValueError("Input too large — trim history or chunk the document.")
JavaScript / Node — same guard with gpt-tokenizer
import { encode } from "gpt-tokenizer";

function numTokens(messages) {
return messages.reduce((n, m) => n + encode(m.content).length + 4, 0) + 2;
}

const CONTEXT_WINDOW = 128_000;
const RESERVE_FOR_OUTPUT = 2_000;

const msgs = [{ role: "user", content: "..." }];
if (numTokens(msgs) > CONTEXT_WINDOW - RESERVE_FOR_OUTPUT) {
throw new Error("Input too large — trim history or chunk the document.");
}

Trim conversation history with a sliding window

For chat apps, keep the system prompt plus the most recent turns that fit, and drop the oldest:

Python — keep system prompt + most recent turns under budget
import tiktoken

def fit_history(messages, model="gpt-4o-mini", budget=120_000):
  enc = tiktoken.encoding_for_model(model)
  size = lambda m: len(enc.encode(m["content"])) + 4
  system = [m for m in messages if m["role"] == "system"]
  rest = [m for m in messages if m["role"] != "system"]
  used = sum(size(m) for m in system)
  kept = []
  for m in reversed(rest):          # newest first
      if used + size(m) > budget:
          break
      kept.append(m); used += size(m)
  return system + list(reversed(kept))

When the input is genuinely large: summarize or chunk

  • Summarize older turns. Periodically replace the oldest history with a short model-generated summary so context stays bounded.
  • Chunk + map-reduce. Split a long document, process each chunk, then combine the partial results in a final call. This is the right pattern for “analyze this whole book/repo.”
  • Retrieve less. In RAG, lower your top-k or shrink chunk size so only the most relevant context goes in.

Or switch to a larger-context model

If you legitimately need more room, move to a model with a bigger window. Confirm the exact size first with the context-window checker — windows differ widely across models and vendors.

How to prevent it

  • Always budget the window as input + output, reserving space for max_tokens before you build the prompt.
  • Cap and prune history on every turn rather than waiting for the overflow.
  • Set max_tokens to what you actually need, not a large default.
  • Pre-flight large requests through a token count in your code path; fail with a clear message instead of a raw 400.
Watch out

Embeddings and other endpoints have their own per-input limits separate from chat. A 400 about input length on /embeddings is the same class of problem — split the input into smaller pieces.

Need a bigger window without re-coding?

If your workload keeps outgrowing one model’s window, routing to a larger-context model on demand is simplest behind a gateway. OpenRouter exposes many models (and their context sizes) through one OpenAI-compatible API, so you can pick a larger window per request. (Affiliate link.)

What to do next

  1. Count input tokens in your request path and reserve room for the output.
  2. Prune or summarize history so chat sessions stay under the window.
  3. Chunk large documents with map-reduce instead of one giant prompt.
  4. Verify the model’s real window and switch up a tier if you truly need more.

Frequently asked questions

Why do I get this error when my input clearly fits the context window?
Because max_tokens is counted too. The window holds input plus the output you reserved — if input is 124K on a 128K model and you set max_tokens to 8K, the total (132K) overflows. Lower max_tokens or trim input.
Is context_length_exceeded retryable?
No. It's an HTTP 400 — the request is malformed by size. Retrying it unchanged fails identically. You must make the request smaller (trim, summarize, chunk) or use a larger-context model.
How do I count tokens before sending?
Use a tokenizer that matches the model — tiktoken in Python, gpt-tokenizer in JS — or paste your text into a token counter tool. Sum the message tokens plus a few tokens of per-message overhead, then compare against the window minus your output reservation.
Should I just always use the biggest-context model?
Not necessarily — larger-context models can cost more per token and don't fix unbounded history. Prune and summarize first; reach for a bigger window only when the input is genuinely large and irreducible.
What's the best way to process a document larger than any context window?
Chunk it and use map-reduce: split into pieces that fit, process each piece, then combine the partial outputs in a final call. This scales to inputs far larger than any single model's window.