Magic Tools
Hands-OnBy CooconSeptember 20, 20264 views7 min read

DeepSeek Says 1M, Claude Code Says 200K: I Measured Both and Neither Number Is the Real Limit

DeepSeek's pricing page lists a 1M context length for both deepseek-flash and deepseek-v4-pro. Point Claude Code at DeepSeek's Anthropic-compatible endpoint (three env vars — I covered the setup and what it costs you separately) and Claude Code reports this for the same model:

"contextWindow": 200000

Two numbers, 5x apart, describing the same model. Which one governs?

I measured it. The answer is neither, and the way it fails is more interesting than either number.

What I measured

Three separate questions that get conflated:

  1. Does the endpoint accept it? — a hard API limit.
  2. Does the model actually use it? — retrieval, not just acceptance.
  3. Does Claude Code let you get there? — the client-side gate nobody documents.

All runs: Claude Code 2.1.270, deepseek-flash, macOS, isolated CLAUDE_CONFIG_DIR. Needle-in-a-haystack uses a unique string planted at position zero (hardest position to retrieve when the haystack is huge) with the question at the very end. Every prompt carries a unique nonce so prompt caching can't contaminate the token counts — the first version of this experiment did not, and produced two rows with identical token counts for payloads differing 2x in size.

Layer 1: DeepSeek's real ceiling is 2^20, not "1M"

Ladder on the raw endpoint, needle at position zero:

Target Real input tokens HTTP Wall Needle found
200K 399,954 200 8.6s
400K 799,823 200 15.8s
950K 949,775 200 19.8s
1040K 1,039,744 200 19.4s
1048K 400 3.7s

At 1,039,744 tokens the model still pulled a string planted at the very beginning, in under 20 seconds. The long context is real, not a spec-sheet number.

The rejection tells you the exact limit:

This model's maximum context length is 1048576 tokens.

1,048,576 = 2^20. So "1M" is binary, not decimal — you get 48,576 tokens more than a literal million.

Context ladder on the raw endpoint: 1,039,744 tokens accepted with the needle retrieved; 1,048,576 is the hard ceiling

The limit includes your output budget

Worth knowing before you size a request. Same input, only max_tokens changed:

Input tokens max_tokens Result
1,045,710 1,000 ✅ 200
1,045,707 8,000 ❌ 400

The error spells out the arithmetic itself:

you requested 1053707 tokens (1045707 in the messages, 8000 in the completion)

So the budget is input + completion ≤ 1,048,576. Ask for a generous max_tokens on a near-full context and you get rejected on input that would otherwise have been fine.

Same input, only max_tokens changed: the 1,048,576 budget covers input plus completion

Layer 2: Claude Code refuses client-side, and it never calls the API

Pipe an oversized prompt into claude -p and you get:

result: "Prompt is too long"
is_error: true
duration_ms: 34
input_tokens: 0

34 milliseconds and zero tokens. Claude Code rejected it locally. DeepSeek never saw the request, and you were never charged.

So far so reasonable — it declared a 200,000 window, it is enforcing a window. Except the number doesn't match either.

Binary search on prompt size, repetitive English filler:

Target user tokens Result Real total input
30K ✅ pass 64,040
80K ✅ pass 114,024
85K ✅ pass 119,022
90K ❌ reject 0 (24ms)
95K / 105K / 112K / 120K / 140K / 150K / 180K / 195K / 205K ❌ reject 0

The gate fires at about 119K total tokens — roughly 60% of the 200,000 it advertises. (~34K of that total is Claude Code's own system prompt and tool definitions, which you pay on every turn.)

Layer 3: the gate isn't measuring tokens at all

Here is the part that matters. Claude Code cannot know DeepSeek's tokenizer, so it has to estimate. If the estimate is the usual characters ÷ 4 heuristic, then the gate should be fixed in characters and drift arbitrarily in real tokens depending on what your text is made of.

Test: same character count, wildly different tokenization density. Repetitive English runs about 5.4 chars/token here; random hex runs about 1.5.

Content Characters Result Real tokens
Repetitive English 459,850 ✅ pass 119,022
High-entropy hex 460,000 ✅ pass 298,819
Repetitive English 486,900 ❌ reject

Same ~460,000 characters. One carried 119K tokens, the other 298,819 — and both passed. The gate did not notice a 2.5x difference in actual token count.

Narrowing the character threshold:

Characters Result Real tokens
470,000 ✅ pass 304,808
478,000 ✅ pass 309,567
482,000 ❌ reject

The gate is at ~480,000 characters. Divide by 4 and you get 120,000 — the chars÷4 heuristic, hard-coded against a budget that is itself 60% of the declared window.

Same character count, 2.5x the real tokens, both pass: the gate counts characters, not tokens

Two consequences that actually bite:

  • The declared 200K window is not a ceiling. 478,000 characters of hex went through carrying 309,567 real tokens, 55% past the advertised window, and the needle came back correctly. Nothing broke — DeepSeek's real limit is 1M, so there was plenty of room.
  • The declared window is not a floor either. Ordinary English gets cut off at ~119K real tokens, well under 200K.

If your work is CJK text, minified code, base64 blobs, or logs — anything that does not tokenize at 4 characters per token — the number on your screen is not describing your situation in either direction.

Layer 4: in practice you never get near any of this

I built a 1.55MB file, 300K tokens, needle on the last line, and asked Claude Code to cat it. It answered correctly. But the usage said:

input_tokens: 34,973

The file never entered the context. Tracing the actual tool calls shows why:

[call]   Bash: cat tail-big.txt
[result] 1,915 chars — "<persisted-output>
         Output too large (1.5MB). Full output saved to: /Users/…"
[call]   Bash: tail -c 2000 tail-big.txt
[result] 1,999 chars — "…The maintenance access code … is PELICAN-7731."

Claude Code persists oversized tool output to a file and hands the model a ~2KB preview. The model then worked around it on its own with a targeted tail -c 2000. Good agentic behaviour — and it means the needle test told me nothing about long context until I noticed.

The threshold is exact:

Bash output Enters context
29,990 chars 29,989 chars — inline
30,010 chars 2,315 chars — persisted

30,000 characters. Any single Bash output above that is written to disk and summarized. Note this is a Bash threshold — in one run the model chose Read instead, which returned 53,656 characters inline for the same file. (That run briefly made my ladder look inconsistent; the cause was the model picking a different tool, not a different limit. I had to pin the tool choice to get a clean measurement.)

Bash output over 30,000 characters is persisted to a file; only a ~2KB preview enters context

So which number wins?

Neither. Ranked by what actually stops you first:

Limit Value Enforced by
Bash output inlining 30,000 chars Claude Code, per tool call
Prompt gate ~480,000 chars (chars÷4 ≈ 120K est. tokens) Claude Code, client-side, 25ms, no API call
Declared window 200,000 tokens nothing — neither floor nor ceiling in practice
Model hard limit 1,048,576 tokens (input + max_tokens) DeepSeek, HTTP 400

The advertised 1M is real and genuinely usable — against the raw API. Through Claude Code you will hit a character-counting gate at roughly a tenth of it, and hit output persistence long before that.

Practical takeaways

  1. Want the 1M? Call the endpoint directly. Claude Code will not take you there.
  2. Don't plan around contextWindow: 200000. It is not enforced as either a minimum or a maximum. The real client-side gate is ~480,000 characters.
  3. Non-English content makes the estimate worse, not better. Chinese, minified JS, base64 — all tokenize far from 4 chars/token, so the gate fires at a real token count that can be double what you expect, in either direction.
  4. Large files are not a context problem, they are a tool-output problem. Anything over 30,000 characters from Bash gets persisted. Use grep/tail/sed to extract what you need instead of cat-ing and hoping.
  5. Size max_tokens against the same budget as your input when you are anywhere near the ceiling.

Pitfalls, condensed

  1. Reusing filler across a ladder silently enables prompt caching — my first run reported identical token counts for payloads differing 2x. Add a unique nonce per request.
  2. A needle at position zero survives truncation — it proves nothing. Put it at the end, then verify the content actually entered context by reading input_tokens.
  3. The model may pick a different tool between runs (Read vs Bash cat), which changes the numbers completely. Pin the tool when you are measuring the tool.
  4. claude -p "$(cat big.txt)" dies with Argument list too long — that is your shell's ARG_MAX, not a Claude Code limit. Pipe via stdin.
  5. "1M" is 2^20 = 1,048,576, and it includes your completion budget.

Tested 2026-09-20, Claude Code 2.1.270 on macOS/Apple Silicon against deepseek-flash (DeepSeek-V4.1-Flash) via https://api.deepseek.com/anthropic. Total API spend for every experiment in this article: ¥5.36 ≈ $0.75, measured by account balance delta. Raw logs retained.

Related Articles

Running Claude Code on DeepSeek: Everything Works, But the Cost Readout Lies by 38x

DeepSeek ships an Anthropic-format endpoint, so you can point Claude Code at it with three environment variables. I ran the whole thing on a real machine: every local tool (Read / Write / Bash / Glob / Edit / subagents) works and produces real side effects, so the short answer is yes, it works. The long answer is the part nobody measured — Claude Code bills DeepSeek tokens at Claude Sonnet rates. Ten identical turns: Claude Code reported $1.71, DeepSeek's actual balance dropped ¥0.32 (≈$0.045). That is a 38x over-report, measured against the invoice, not a price list. Also inside: the official docs are wrong about unknown model names (they 400, they don't fall back), v4-pro returns thinking blocks by default so a small max_tokens looks like an empty reply, and one failure that looks like DeepSeek's fault but isn't.

claude-codedeepseek+5
hands-onSep 20, 20268 min
7

Service Up, Ports Open, Certs Valid, VPN Dead for 4 Hours: Tailscale Took Over DNS and Left the Proxy Box With No Upstream

A Los Angeles VPS running sing-box (VLESS-REALITY + Hysteria2) lost its VPN the day after Tailscale was installed. systemctl, ports and certificates were all fine. The root cause was in /etc/resolv.conf: Tailscale manages DNS by default, the tailnet had no global nameservers, and when dhclient renewed its lease tailscaled read an empty resolv.conf and dropped its upstream list. From then on every public domain got SERVFAIL, and the REALITY handshake could not even resolve www.apple.com. Full timeline, the evidence for each step, three fixes, and the rules we added to CLAUDE.md so an AI assistant (Claude Code) does not walk into this again.

claude-codetroubleshooting+8
pitfallsSep 17, 20266 min
69

Reproducing an Injection Chain That Cracks Claude Code Auto Mode: the Model Refuses the Malicious Binary, Then Writes Code That Pwns Itself

In late August embracethered published an attack chain where a plain 'summarize this page' request drags auto-mode Claude Code to a 60–80% code-execution rate — while Anthropic's commissioned third-party test reported 0.00%. I took the chain apart and tested it stage by stage in an isolated environment: the endpoint that nudges the model from WebFetch to curl, and the crux — the model's own 'safe' decision to refuse the unknown binary and write its own Python decoder instead lands straight on a same-name struct.py planted in the extracted directory. The deterministic parts (branching + module-shadow poison + mitigation controls) reproduce fully on my machine with real evidence; the live end couldn't complete a full RCE here because the classifier rate-limited and failed closed — flagged honestly. Ends with mitigations that actually help.

claude-codeauto-mode+5
hands-onAug 31, 20269 min
169

Cracking Open Claude Code's Auto-Mode Classifier: A 116K-Char System Prompt, Dissected Line by Line

My earlier retest confirmed auto mode calls the session model as a classifier before each risky Bash — but what it receives stayed a black box. This time I captured the full request: a 116,879-char system prompt opening 'You are a security monitor for autonomous AI coding agents.' I quote it verbatim to dissect the threat model, two-tier rules (1 HARD BLOCK / 68 SOFT BLOCK / 17 ALLOW), and two-stage evaluation — stage 1 grades harm only, stage 2 layers intent on top. Every number read out this session.

claude-codepermissions+5
hands-onAug 30, 202612 min
254