Claude API Context Window Fix 6 min read

Claude Context Window Exceeded — Fix "Prompt Is Too Long"

You sent a request to Claude and got back prompt is too long: 214583 tokens > 200000 max. Here is why it happens and how to fix it — with token counting, history truncation, prompt caching, and extended thinking budget strategies.

Anthropic API live status

Anthropic API — live status

Updated every 5 minutes · Full incident history →

Full status →

Context window vs. max_tokens — what counts

All current Claude models share a 200,000 token context window: claude-3-haiku-20240307, claude-3-5-sonnet-20241022, claude-sonnet-4-6, and claude-opus-4-8. The window is shared between everything:

total_tokens = system_prompt_tokens + all_message_tokens + tool_result_tokens + max_tokens_reserved_for_output

max_tokens is only the output budget you reserve. If input_tokens + max_tokens > 200000 you get a second error: "max_tokens exceeds context window". Set max_tokens to what the response actually needs, not the theoretical maximum.

Fix 1: Count tokens before sending

Use the countTokens endpoint (exact, free)

Anthropic provides a token counting endpoint that returns the exact count without consuming API credits or producing output. Add a guard before every expensive call:

import anthropic

client = anthropic.Anthropic()

system = "You are a helpful assistant..."
messages = [
    {"role": "user", "content": "Summarize this 80-page document: ..."},
    {"role": "assistant", "content": "Here is the summary..."},
    {"role": "user", "content": "Now compare it to this other document: ..."},
]

# Count tokens before sending — no credits used
token_count = client.beta.messages.count_tokens(
    model="claude-3-5-sonnet-20241022",
    system=system,
    messages=messages,
)
print(f"Input tokens: {token_count.input_tokens}")  # e.g. 187432

CONTEXT_LIMIT = 200_000
MAX_OUTPUT = 4096

if token_count.input_tokens + MAX_OUTPUT > CONTEXT_LIMIT:
    print("Too long — triggering truncation before send")
    # ...truncate messages (see Fix 2)
else:
    response = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=MAX_OUTPUT,
        system=system,
        messages=messages,
    )

Fast estimation (no API call): when you need a quick check without an extra round-trip, divide character count by 4 for English prose (3 for code-heavy content). This is accurate to within ~10%:

def estimate_tokens(text: str, is_code: bool = False) -> int:
    chars_per_token = 3 if is_code else 4
    return len(text) // chars_per_token

# Estimate total input
total = estimate_tokens(system)
for msg in messages:
    content = msg["content"] if isinstance(msg["content"], str) else ""
    total += estimate_tokens(content) + 4  # 4 overhead per turn

print(f"Estimated tokens: {total}")

Fix 2: Truncate or summarize conversation history

Drop oldest turns (sliding window)

The simplest approach: keep only the most recent N turns. Always keep the system prompt intact — only drop message history:

def trim_history(messages: list, max_turns: int = 10) -> list:
    """Keep the last max_turns complete user/assistant pairs."""
    # messages come in pairs: [user, assistant, user, assistant, ...]
    # keep last max_turns pairs = last max_turns * 2 messages
    keep = max_turns * 2
    if len(messages) > keep:
        return messages[-keep:]
    return messages

# Or trim until it fits under token budget
def trim_to_fit(client, model, system, messages, max_tokens_out=4096):
    limit = 200_000 - max_tokens_out
    while len(messages) > 2:
        count = client.beta.messages.count_tokens(
            model=model, system=system, messages=messages
        )
        if count.input_tokens <= limit:
            break
        # Drop oldest pair (user + assistant)
        messages = messages[2:]
    return messages

Compress with a rolling summary

For long-running assistants, periodically ask Claude to summarize old turns, then replace them with a single context message:

def compress_history(client, model, messages, keep_recent=4):
    """Summarize early turns, keep recent turns verbatim."""
    if len(messages) <= keep_recent * 2:
        return messages

    old = messages[:-keep_recent * 2]
    recent = messages[-keep_recent * 2:]

    summary_resp = client.messages.create(
        model=model,
        max_tokens=1024,
        messages=[
            *old,
            {"role": "user", "content": (
                "Summarize the conversation above in 3-5 sentences, "
                "capturing all key facts, decisions, and context."
            )},
        ],
    )
    summary_text = summary_resp.content[0].text

    compressed = [
        {"role": "user", "content": f"[Earlier conversation summary]: {summary_text}"},
        {"role": "assistant", "content": "Understood. I have that context."},
        *recent,
    ]
    return compressed

Fix 3: Cache system prompts to save tokens and cost

Prompt caching for repeated context

If your system prompt or reference document is large and stays the same across many requests, enable prompt caching. Cached tokens cost 10% of normal input price on re-use, and the cache lasts 5 minutes. Add cache_control to the last block you want cached:

response = client.beta.prompt_caching.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "You are an expert code reviewer...",
        },
        {
            "type": "text",
            "text": entire_codebase_as_string,  # could be 50K+ tokens
            "cache_control": {"type": "ephemeral"},
        },
    ],
    messages=[{"role": "user", "content": "Review the auth module"}],
)
// TypeScript — prompt caching
const response = await client.beta.promptCaching.messages.create({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  system: [
    { type: 'text', text: 'You are an expert code reviewer...' },
    {
      type: 'text',
      text: entireCodebaseAsString,
      cache_control: { type: 'ephemeral' },
    },
  ],
  messages: [{ role: 'user', content: 'Review the auth module' }],
});

// Check cache usage in response
console.log(response.usage.cache_read_input_tokens);   // tokens served from cache
console.log(response.usage.cache_creation_input_tokens); // tokens written to cache
Tip: Prompt caching does not shrink the context window — the tokens still count toward the 200K limit. Its value is cost and latency reduction, not capacity expansion.

Fix 4: Extended thinking — budget tokens carefully

Extended thinking eats into your context budget

Extended thinking reserves thinking_budget_tokens from the 200K context for internal reasoning. The thinking is not returned as text output, but it does count. If your input is already large, a high thinking budget causes "max_tokens + thinking_budget exceeds context":

# Context budget formula with extended thinking:
# input_tokens + thinking_budget_tokens + max_tokens <= 200_000

input_tokens = 150_000   # large document
thinking_budget = 10_000
max_tokens = 4_096

if input_tokens + thinking_budget + max_tokens > 200_000:
    # Reduce thinking budget
    thinking_budget = 200_000 - input_tokens - max_tokens - 1_000  # 1K safety margin
    thinking_budget = max(1_024, thinking_budget)  # minimum useful budget

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=max_tokens,
    thinking={
        "type": "enabled",
        "budget_tokens": thinking_budget,
    },
    messages=[{"role": "user", "content": prompt}],
)
  • Reasonable budgets: 1,000–2,000 tokens for straightforward tasks; 4,000–8,000 for complex reasoning; only 10,000+ for the hardest multi-step problems.
  • Extended thinking only on claude-opus-4-8 and claude-sonnet-4-6 — it is not available on Haiku models.

Get an email the next time Anthropic goes down

Outage alerts for Anthropic, straight to your inbox. No account needed, unsubscribe in every email.

Watching more than one service? A free account covers 5 services + a daily digest — and Pro is currently free.

FAQ

What does "claude prompt is too long" mean?

The error prompt is too long: X tokens > 200000 max means the total input — system prompt plus all conversation turns plus tool results — exceeds the 200K token context window. The fix is to count tokens before sending and remove old turns, summarize history, or split long documents.

What is the difference between context window and max_tokens?

The context window (200K) is total capacity for input and output combined. max_tokens is only the output budget you reserve inside that window. If input_tokens + max_tokens > 200000, you get a "max_tokens exceeds context" error. Set max_tokens to what you actually need, not the theoretical maximum.

How do I count tokens before sending to Claude?

Use client.beta.messages.count_tokens(model=..., system=..., messages=...). It returns exact token counts without spending API credits. For a quick offline estimate: 1 token ≈ 4 characters for English prose, 1 token ≈ 3 characters for code.

How does extended thinking affect the context window?

Extended thinking's budget_tokens are reserved inside the 200K limit. Formula: input + thinking_budget + max_tokens <= 200000. Scale the thinking budget to task complexity — most tasks work well with 1,000–8,000 tokens.

Related guides