[BUG] 'claude-api' is consuming entire context
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When attempting to ask a question in non-interactive mode (prompt was "Have the changes for 'non-interactive' usage rates gone into effect?"), the 'claude-api' skill is being loaded and consuming the entire context, resulting in the 'Prompt is too long' error.
Claude's summary of the issue:
Session metadata (anonymized):
sessionId: [REDACTED]
cwd: /home/[USER]/delete/tmp
version: 2.1.176
1. User prompt sent:
{"type":"user","message":{"role":"user","content":"Have the changes for 'non-interactive' usage rates gone into effect?"},"entrypoint":"sdk-cli"}
2. Skill listing loaded at session start (showing claude-api among active skills):
{"attachment":{"type":"skill_listing","names":["grill-me","lazydm-session","deep-research","skill-creator:skill-creator","update-config","keybindings-help","verify","code-review","simplify","fewer-permission-prompts","loop","schedule","claude-api","run","init","review","security-review"],"isInitial":true}}
3. Claude decides to invoke the claude-api skill:
{"message":{"content":[{"type":"tool_use","name":"Skill","input":{"skill":"claude-api"}}],"stop_reason":"tool_use"}}
4. Skill content loaded — the full contents of the bundled claude-api SKILL.md are injected as a tool result. The content includes complete API reference documentation for C#, Go, Java, PHP, Python, TypeScript, cURL, managed agents, model migration guides, and more. Total size is several hundred KB.
5. Immediate error:
{"message":{"content":[{"type":"text","text":"Prompt is too long"}],"error":"invalid_request","isApiErrorMessage":true}}
---
Summary for bug report: In -p (non-interactive) mode, a 10-word conversational prompt triggered the bundled claude-api skill, which loaded its entire documentation contents into the context. The resulting prompt exceeded the model's context limit, producing a "Prompt is too long" error on a fresh session. Running with --safe-mode (which disables skills) resolves the issue.
What Should Happen?
The skill shouldn't consume the entire context, blocking usage.
Error Messages/Logs
Steps to Reproduce
While on Claude Code version 2.1.176: claude -p "Have the changes for 'non-interactive' usage rates gone into effect?
"
Claude Model
Sonnet (default)
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.176
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
Other
Additional Information
I am using the Alacritty terminal on Manjaro Linux
Showing cached comments. Read the full discussion on GitHub ↗
9 Comments
Hitting the same.
Some questions trigger loading full ˜200K token claude-api.
This is a killer if using a 200K context window model, because you loose most of your context during the resulting compaction.
Also, the full claude-api can be re-loaded and consume more context each time.
Also, the ˜200K tokens are counted as Messages, not Skills, so higher cost.
----
Good catch — this is an important distinction in how skills work:
"Skills" (1.1k) = the skill descriptions/headers that are always pre-loaded as part of the system setup. These are tiny summaries of what each skill does.
"Messages" (895k) = when a skill is triggered, its full content gets injected into the conversation as a tool result or response — it lands in the message stream, not the system prompt.
This has real cost implications:
**The ideal architecture would be: skill content → system prompt with cache_control → cached after first request. Instead it's: skill content → message history → full price every turn, accumulating across the session.
This is probably worth filing as a specific feedback item: "skill content should be injected into the system prompt (with caching) rather than the message stream." That would drop the effective cost of using skills from ~$3/MTok to ~$0.30/MTok after the first load.**
Still reproduces on v2.1.187, with concrete numbers to replace the "several hundred KB" estimate.
A trivial conversational lookup (
/claude-apiinvoked with args "Sonnet 4.5 and Sonnet 4.6 release dates") triggered the skill. TheSkilltool result itself is tiny — justLaunching skill: claude-api— but launching the skill injected a single synthetic user message of 733,881 characters. The next API request reported:So a ~10-word lookup cost ~293k tokens in one shot.
Mechanism (confirmed from the transcript): the injected payload is the
claude-apiSKILL.md plus the entire bundled reference tree concatenated into one block — not just SKILL.md, and not lazy-loaded. The injected text contains 445 file-path markers and top-level headings for every bundled file: all 8 SDK languages (Python, TypeScript, Java, Go, Ruby, C#, PHP, cURL) × {README, tool-use, streaming, batches, files-api, managed-agents} plus theshared/*.mddocs (model-migration, prompt-caching, tool-use-concepts, agent-design, managed-agents-*, etc.). It extracts to…/bundled-skills/2.1.187/<hash>/claude-api.Yet the SKILL.md body itself instructs the model to detect the project language and read only the relevant
{lang}/files on demand — but the launch front-loads the whole tree anyway, defeating that design. This makesclaude-apiby far the heaviest bundled skill; most skills inject only their SKILL.md (a few KB) and Read reference files as needed.#70158 (inject skill content into the cached system prompt rather than message history) would reduce per-turn cost, but the more direct fix here is to honor the on-demand reading guide the SKILL.md already describes instead of concatenating every bundled file into the launch payload.
This happened to me as well. I lost ~150k and maxed out my context window in a minute because I mentioned claude 4 times in a single prompt. The bundled skill's trigger condition is too broad and should be scoped to /claude-api explicit invocations only, not ambient keyword
matching.
Adding more context to this. I dug a bit deeper and the context bomb definitely looks like unintended behavior. Still present on 2.1.196.
The
claude-apiskill loads more than just a typical SKILL.md (already big at ~15-25K tok). It loads the entireshared/directory (146k tok) and a language directory e.g.typescript/(19.6k tok) orpython/(22.7k tok). I found this stuff in/tmp/claude-1000/bundled-skills/2.1.196/{hash_here}/claude-api/I measured each of these files with Claude's official token count API. Here's what I confirmed loaded into the session for my repro:
(SKILL.md seems to come from the harness or something rather than a file, so couldn't measure that)
What leads me to believe this is not intended behavior is the kinds of stuff in
shared/. Someone vibe coding a 30min dashboard wouldn't care about migrating old models. yet the entire 44k tokens ofmodel-migration.mdget loaded into context. same deal with managed agents (59k tok total):And the first few lines in
model-migration.mdimply that it should be gated by the skill's arg, not loaded upfront:Hope this can be prioritized as taking a 180k hit to context is effectively a breaking bug - we can't even disable the skill or trigger since it's built-in, so it's forced compaction or a rewind. Even as a 1mil ctx user who WANTS to work with Claude API, going past 200k ctx degrades the quality enough that I'd rather just paste the relevant API info manually.
You can disable the built-in
claude-apiskill today without--safe-mode(which nukes all skills). Add a targeteddenypermission in~/.claude/settings.json:This blocks invocation of the skill, which is where the ~180k-token
SKILL.mdpayload gets injected (step 4 in the OP). Since the bomb only loads on invocation, denying invocation prevents the context blow-up entirely — no forced compaction, no rewind.Caveat: the small skill-listing entry (the one-line description + its TRIGGER/SKIP block) is still injected at session start regardless, because that happens before permissions are consulted — but that's a few hundred tokens, not the several-hundred-KB reference dump. So
denygets you ~99% of the way: you keep every other skill, andclaude-apisimply becomes un-callable instead of context-fatal.Still very much a bug worth fixing (the full multi-language reference shouldn't load upfront — it should be gated behind the skill's
arg, as themodel-migration.mdheader itself implies), but thedenypermission is a clean per-skill opt-out in the meantime.Still reproduces on 2.1.204 — with a forensic breakdown that pins this to load-time over-inlining (not a packaging/missing-file problem), plus a subagent failure mode not yet mentioned here.
Confirming this is alive on 2.1.204 (reports above top out at 2.1.201 / 2.1.196). A single
Skill(claude-api)invocation measured 303,328cache_creation_input_tokensin one turn — in line with #74621 (299,218) and #74473 (210,658).What actually gets injected
Extracted the raw skill-result message from the session transcript and diff'd it against the on-disk bundle. The injected blob is the SKILL.md body plus the verbatim contents of exactly these files:
shared/**— including the full Managed Agents suite (19 files) and a 144 KBshared/model-migration.mdtypescript/**, auto-selected from the repo'spackage.json)shared/alone is ~200K tokens and is inlined in full on every invocation, none of it task-gated — even for a one-line question.This is runtime over-inlining, not a bad bundle or a missing SKILL.md
I checked whether the bundle was just missing its SKILL.md and falling back to a dump. It isn't:
SKILL.mdinanthropics/skillsis a lean ~50–55 KB router that only references the docs and defers reading — e.g. "Read the language-specific Claude API source —{language}/claude-api/", "Readshared/model-migration.mdimmediately", "Full docs via WebFetch inshared/live-sources.md." It does not inline anything. The skill is authored correctly for progressive disclosure.bundled-skills/<ver>/<hash>/claude-apidir intentionally contains only the reference tree (noSKILL.mdfile); the SKILL.md body is compiled into theclaudebinary.shared/+ only the detected language and drops the other 7. That selection can only be made at load time from the user's project (package.json/pyproject.toml).So Claude Code reads the lean router, runs language detection, and then pre-inlines all of
shared/+ the whole detected-language dir into a single skill-result message — bypassing the router's own task-routing tables ("read only{lang}/README.md"). The flattening is introduced by the loader at invocation, not by the skill package.Failure mode not yet noted here: background subagents die silently
When a subagent triggers this skill it terminates with
Agent terminated early due to an API error: Prompt is too longbefore doing any work. This is worse than the interactive case because:/contextto inspect,In our case two research subagents on Sonnet were killed this way; only an agent that never invoked the skill succeeded.
Environment
Claude Code 2.1.204 (native binary, Linux); Sonnet 5 and Opus 4.8. The injection mechanism is identical across models — it's assembled client-side, independent of provider/gateway.
Repro
Two independent triggers, both reproduce:
A — explicit natural-language ask (Sonnet 5, interactive):
claude-apiskill loads and the single skill-result balloons context by ~300K.B — project-detected invocation:
package.json/pyproject.tomlso language detection fires)./claude-api(or ask "add an Anthropic SDK call to this file")./contextimmediately after "Successfully loaded skill."Expected: Skills ≈ 5–20K tokens (router body; refs read on demand). Actual: ~300K jump, or
Prompt is too long/Context limit reachedon a 200K model.Note the trigger is trivially easy to hit — a one-line question that merely mentions the Claude API and a model name pulls in the full ~300K payload.
Suggested fix
Inject only the SKILL.md router on load and let the model
Readshared/and language files on demand, as the router already instructs. At minimum, stop inlining the fullshared/tree (especiallymodel-migration.mdand the 19-file Managed Agents suite) unless the task requires it.Still reproduces on Claude Code 2.1.215, and I have a paired background-subagent failure that isolates the skill load as the cause.
Environment
claude-code-guideagentsclaude-haiku-4-5-20251001), 200K contextPaired reproduction
Both children were spawned from the same parent with the same agent type, resolved model, permission mode, tool list, and session. Their initial requests were effectively identical:
The failed child then called:
That invocation inserted a 799,060-character skill payload into its transcript. The immediately following model attempt recorded zero input/output tokens and failed with:
There was no retry. The successful sibling never invoked
claude-apiand completed normally.This rules out inherited parent context as the cause in this case. The parent had grown considerably between the two spawns, but neither child inherited that live context in its initial request.
Payload size
The extracted 2.1.215 bundled
claude-apidirectory contains 733,212 raw bytes of documentation. The injected wrapper expands that to 799,060 characters. It includes the shared reference corpus and multiple SDK-language trees;shared/model-migration.mdalone is about 145 KB.The trigger was a Claude Code hooks and Agent SDK documentation question. The agent's skill listing instructed it to load
claude-apiwhenever the prompt named Claude or Anthropic, so an operational Claude Code question pulled in the API corpus.Expected behavior
claude-code-guidehandle Claude Code operational/documentation questions without triggering the API skill.The 2.1.215 payload now hard-fails a normal 27K-token Haiku subagent immediately, so this also affects background-agent reliability, where the user gets little context about why the child disappeared.
Hving the same issue on 2.1.218
Still reproduces on Claude Code 2.1.219 (macOS, cmux) with Opus 5 / 1M context.
Reproduction: immediately after using
/model, I asked:Claude invoked the built-in
Skill(claude-api)even though this was a subscription-usage question, not an API-development task.Transcript measurements:
/contextafterward: 309.7k total, with 264.6k under MessagesThis appears to combine two problems: false-positive activation and eager inlining of the shared/reference corpus instead of progressive disclosure. The activation may be related to #66643 because both Claude Code's
/modeloutput and my prompt contained model names, but the client transcript alone cannot establish which exact trigger fired.Expected behavior: a subscription-usage question should not activate
claude-api; if API documentation is required, only the relevant topic should be loaded on demand.Anthropic feedback ID:
b4fb5276-bbf6-41d1-81e5-d2c1231c7ebc