Claude API 400 "prompt is too long": Causes and Fixes
You call /v1/messages and get HTTP 400 invalid_request_error starting with prompt is too long. Here is what counts against the context window, how the input + max_tokens rule works on current models, and how to measure and shrink a prompt.
Quick answer
"prompt is too long" means the input alone — system prompt, every message, tool definitions, images and documents — is bigger than the model's context window. The request is rejected before generation starts, so retrying or lowering max_tokens will not help; only a smaller input will. Measure the request with POST /v1/messages/count_tokens, then drop or summarize old turns, shrink large tool results, or split the job. On Claude 4.5 and newer models, a large max_tokens on its own does not trigger this error.
Symptoms and What the Error Means
On Anthropic's native Messages API the body looks like this:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "prompt is too long: 1048213 tokens > 1000000 maximum"
},
"request_id": "req_011CSHoEeqs5C35K2UUqR7Fy"
}Anthropic's docs name this error but don't publish the full message template; the N tokens > M maximum tail is the format seen in public error reports, and the numbers above are illustrative. In code, match on the prompt is too long prefix, not the numbers.
On models older than Claude 4.5 you may instead hit a check on input plus output. Community reports show it worded like this:
input length and `max_tokens` exceed context limit: 198882 + 21333 > 200000, decrease input length or `max_tokens` and try againDon't confuse it with its neighbors:
- 413
request_too_large— the HTTP body has too many bytes, not too many tokens. See 413 request too large. max_tokensabove the model's output cap — a different 400 about the output limit. See max_tokens too large.stop_reason: "model_context_window_exceeded"— not an error at all: a 200 response that stopped because generation filled the window.
How the Context Window Is Counted
Per Anthropic's docs, everything in the request counts: the system prompt, every entry in messages (including tool results, images and documents) and your tool definitions — plus the output for the turn, thinking included. With prompt caching, input_tokens, cache_read_input_tokens and cache_creation_input_tokens all count.
Claude Opus 5.5, Sonnet 5.5 and Haiku 5.5 (and the other current models) have a 1M-token window by default, no beta header needed, with up to 128K output tokens. Older models, including Claude Sonnet 4.5, have 200K. A request can carry at most 600 images or PDF pages (100 on 200K models).
The input + max_tokens rule
The behavior changed with Claude 4.5:
| Situation | Claude 4.5 and newer | Earlier models |
|---|---|---|
| Input alone exceeds the window | 400 "prompt is too long" | 400 "prompt is too long" |
Input fits, but input + max_tokens exceeds the window | Accepted; if generation reaches the limit, it stops with stop_reason: "model_context_window_exceeded" | 400 validation error (opt in to the new behavior with the model-context-window-exceeded-2025-08-26 beta header) |
So on current models you can set max_tokens generously without pre-computing headroom — but you must check stop_reason and treat model_context_window_exceeded as a truncated answer.
Hidden growth: thinking blocks and the new tokenizer
- Kept thinking blocks. On Claude Opus 4.5 and later Opus models, Sonnet 4.6 and later Sonnet models, and Haiku 5.5, thinking blocks from previous turns stay in context and count as input, so agent sessions grow faster than the visible text suggests.
- Tokenizer change. Per Anthropic, Claude 4.7 and later models use a tokenizer that produces roughly 30% more tokens for the same text. A prompt that fit an older model can overflow after migration; recount against the model you call.
Fix 1: Measure Before You Send
The token counting endpoint accepts the same inputs as a Messages request and returns input_tokens. It is free to use and has its own rate limit, separate from message creation.
curl https://api.anthropic.com/v1/messages/count_tokens \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5-5",
"system": "You are a code reviewer.",
"messages": [{"role": "user", "content": "Review this diff: ..."}]
}'
# => {"input_tokens": 1234}A preflight check in Python:
import anthropic
client = anthropic.Anthropic()
MODEL = "claude-sonnet-5-5"
CONTEXT_LIMIT = 1_000_000 # from the model's page in Anthropic's docs
HEADROOM = 0.9 # the count is an estimate; leave room for output
def fits(system, messages, tools=None):
kwargs = {"model": MODEL, "system": system, "messages": messages}
if tools:
kwargs["tools"] = tools
n = client.messages.count_tokens(**kwargs).input_tokens
return n, n < CONTEXT_LIMIT * HEADROOMKnow its limits: the count is an estimate, and the endpoint rejects server tools, the MCP connector, and image/document blocks with a url or file source (send base64 to count those). In production, also log usage from every response to see how close each conversation is to the ceiling.
Fix 2: Trim History Without Breaking It
Dropping the oldest turns is the obvious fix, and it has two traps.
Trap 1: orphaned tool results. If you cut between an assistant tool_use and the user tool_result that answers it, you swap this error for tool_use without tool_result. Always cut at a plain user turn.
Trap 2: thinking-block signatures. On Claude Opus 5.5, Sonnet 5.5 and Haiku 5.5, a replayed thinking block must match the prefix it was produced in. Anthropic lists client-side compaction that keeps recent thinking verbatim as a cause of the Invalid signature in thinking block 400; its documented remedy is to strip those blocks.
def is_plain_user(msg):
if msg["role"] != "user":
return False
c = msg["content"]
return isinstance(c, str) or not any(b.get("type") == "tool_result" for b in c)
def trim_history(messages, keep_last=20):
trimmed = messages[-keep_last:]
# 1. Start on a plain user turn so no tool_result loses its tool_use
while trimmed and not is_plain_user(trimmed[0]):
trimmed = trimmed[1:]
# 2. Kept thinking blocks no longer match the shortened prefix: drop them
out = []
for m in trimmed:
if m["role"] == "assistant" and isinstance(m["content"], list):
m = {**m, "content": [b for b in m["content"]
if b.get("type") not in ("thinking", "redacted_thinking")]}
out.append(m)
return outThis assumes plain-dict messages (convert SDK objects with .model_dump()). Trim only before appending a fresh user turn, never mid tool loop.
To avoid managing this yourself, use Anthropic's server-side compaction (beta, Claude 4.6 and later), which summarizes earlier turns on the server, or context editing, which clears old tool results and thinking blocks. Per the docs, neither triggers the signature error.
Fix 3: Shrink What You Send
Many oversized prompts are a few huge blocks, not a long conversation:
- Tool results. Log dumps, full file reads and raw HTML are the usual offenders in agents. Truncate or summarize them before returning them, or let context editing clear stale ones.
- Documents. Retrieve relevant chunks instead of pasting a whole corpus; split dense PDFs by section.
- Tool definitions. Every tool schema is input on every request. Drop tools the task doesn't need, or defer them with Anthropic's tool search tool.
- Summaries. Replace old turns with a short summary message; one extra call keeps the history small from then on.
Fix 4: Know What Prompt Caching Does — and Doesn't
Caching is not a context fix. Anthropic states that cached prefixes still occupy the context window; caching changes what you pay for those tokens, not whether they count. It can still lower the bill on long, stable prefixes, but there is a trade-off: cache writes are billed above the normal input rate, so caching a prefix that is not reused soon costs more than not caching it.
Finally, handle the non-error case: when a response comes back with stop_reason == "model_context_window_exceeded", the answer was cut off by the window, not by max_tokens — trim history (Fix 2) before asking the model to continue.
If You're Calling Claude Through byesu
byesu is an AI API gateway with an OpenAI-compatible endpoint (https://byesu.com/v1) and an Anthropic-native endpoint (/v1/messages on the same host), billed pay-as-you-go with no subscription. Two points matter for this error:
- The window belongs to the model. A gateway cannot enlarge it:
claude-opus-5-5,claude-sonnet-5-5andclaude-haiku-5-5(also callable as dotted aliases likeclaude-opus-5.5) have the limits Anthropic publishes. On/v1/chat/completionsthe same failure may arrive wrapped in an OpenAI-style error object, so match on the "prompt is too long" text rather than the JSON shape. - Trimming is also a cost fix. With pay-as-you-go billing, every turn of history you resend is billed again as input. In Claude Code (
ANTHROPIC_BASE_URL=https://byesu.com, without/v1), run/compactbefore a session nears the limit instead of waiting for the 400.
To get started, create a token in the console and point your SDK at the endpoint above. Full setup: Quick Start.
FAQ
What does "prompt is too long" mean in the Claude API?
It is a 400 invalid_request_error returned when the input alone — system prompt, messages, tool definitions, images and documents — exceeds the model's context window. The request is rejected before any generation, so retrying the same request or lowering max_tokens will not fix it; you have to send fewer input tokens.
Does max_tokens count toward the Claude context window?
The output Claude generates counts toward the window, but on Claude 4.5 and newer models the API no longer rejects a request just because input plus max_tokens exceeds the window. It accepts the request and, if generation reaches the limit, stops with stop_reason "model_context_window_exceeded". Earlier models return a validation error instead, unless you send the model-context-window-exceeded-2025-08-26 beta header.
How do I count tokens before sending a Claude API request?
Send the same model, system, messages and tools to POST /v1/messages/count_tokens; the response contains input_tokens. The endpoint is free with its own rate limit, but the result is an estimate, and it rejects server tools, the MCP connector and url or file image/document sources, so send base64 when you need to count media.
Does prompt caching help with "prompt is too long"?
No. Cached prefixes still occupy the context window — caching changes what you pay for those tokens, not whether they count. To fix the error, remove or summarize content. Caching can still lower cost on a long, stable prefix you reuse often, but cache writes are billed above the normal input rate, so caching content you don't reuse costs more.
Why did my prompt start failing after switching to a newer Claude model?
Anthropic notes that Claude 4.7 and later models use a newer tokenizer that produces roughly 30% more tokens for the same text, and current Opus and Sonnet models also keep earlier thinking blocks in context. A prompt that fit an older model can therefore overflow on a newer one. Recount with count_tokens against the model you actually call.
