The seven failures you'll hit most — invisible files, out-of-context errors, silent hooks, MCP servers that won't start, runaway tokens, rate limits, and auth loops — with the exact fix for each.
This chapter is organized by symptom, not by cause. You landed here because something is broken — find the heading that matches what you're seeing, read the "likely cause" list in order (most common first), and apply the fix. Most of these take under two minutes once you know where to look.
Claude Can't See My File
Symptom — Claude says a file doesn't exist, or reads an old version, or claims a folder is empty when you can see files in your editor.
Likely causes (check in this order)
- Claude's cwd isn't where you think it is. Subagents especially start with their own cwd. This is the #1 cause.
.gitignoreorpermissions.denyis hiding the file. Claude respects gitignore for searches;permissions.denyblocks reads explicitly.- Wrong path or case mismatch.
components/Button.tsxvscomponents/button.tsx— macOS forgives, Linux doesn't. - Git worktree confusion. You opened Claude from
../repo-featbut keep giving it paths from../repo. - File type excluded. Very large files, binaries, and some lock files are skipped silently.
Fix
Before you look for the file, run:
1. pwd
2. ls -la
3. git check-ignore -v <the-path-you-expect>
4. cat .claude/settings.json | jq '.permissions.deny // []'
5. git worktree list
Then tell me where you think the file is and where you actually are.
If .gitignore is filtering it out of search results, point Claude at the explicit path with Read — gitignore affects listing and searching, not explicit reads. If permissions.deny is blocking it, remove or narrow the rule in .claude/settings.json.
Prevention
Get .gitignore right before anything else, and use permissions.deny surgically — see Foundations → Hiding Files from Claude. The 30-second setup prevents a full category of "it's missing" confusion.
Out of Context Errors
Symptom — "conversation too long" error, sudden refusals that feel off, Claude forgets instructions from earlier, or /context shows 80%+.
Likely causes
- You've crossed the 200K ceiling. Hard limit. The request can't be sent.
- You're above 80% and performance is degrading. Not yet an error — but the next prompt might be.
- A tool dumped a huge blob into context. A file read, a
curloutput, a log that streamed thousands of lines. - A subagent returned a massive summary. Subagents should summarize to ~2K. Sometimes they don't.
Fix (in order of escalation)
/context # see the breakdown
/compact # compresses conversation history (see the warning below)
Before I /clear, write .claude/handoff.md with:
- Current status (done / not done)
- The next concrete step
- Open questions
- Exact commands to resume
Keep it under 40 lines.
Then /clear, start a new session, and open the handoff. See Workflows → Context Handoff for the full pattern.
# Set the StatusLine to show your context percentage
# See Foundations → The Context Window for the settings.json snippet.
/compact is not a free lunch
/compact rewrites your history into a summary. Useful, but Claude loses the literal turns — the exact prompt wording, the exact tool outputs. For anything where detail matters (bugfix traces, mid-review conversations), a handoff doc beats /compact. See Workflows → Session Management.
Hook Didn't Fire
Symptom — You wrote a hook in .claude/settings.json. Claude does the trigger action. Nothing happens. No error, no log, nothing.
Likely causes
- Settings file isn't loaded. Wrong path (
.claude/settings.local.jsonvssettings.json), or JSON syntax error that silently invalidates the file. - Matcher doesn't match.
"Edit|Write"matches literally — if you meant to catchMultiEdit, add it explicitly. - Wrong event name.
PostToolUse≠postToolUse. Case-sensitive. - Command fails silently. Hook command exits non-zero before doing anything visible.
- Timeout too short. Hook takes 15 seconds, default timeout kills it at 10.
Fix — the two-line diagnostic hook
Add this to .claude/settings.json first. It proves the hook plumbing works, separate from whatever your real hook is trying to do.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "echo \"[hook] $(date) fired on $(echo \\\"$CLAUDE_TOOL_NAME\\\")\" >> /tmp/claude-hook.log",
"timeout": 5
}
]
}
]
}
}
Trigger an edit. Then:
tail -f /tmp/claude-hook.log
- Log appears with every edit → plumbing works, your real hook has a bug inside it.
- Log is empty → the settings aren't being loaded. Validate JSON:
jq . .claude/settings.json. Confirm the file path.
Prevention
Always end real hook commands with an explicit exit code and an echo you can grep for. A hook that fails silently is worse than no hook — you'll trust a gate that isn't there. See Extensions → Hooks.
MCP Won't Connect
Symptom — MCP tools don't appear in Claude's tool list. Or claude mcp list shows the server as failed. Or you get a timeout when Claude tries to call an MCP tool.
Likely causes
- The command can't be found.
npx -y …is usually fine, butpython -m somethingfails if you're in the wrong venv. - Env var interpolation wrong.
"${env:API_KEY}"requires the env var to be set in the parent shell beforeclaudestarts. - Package not installed yet. First
npx -yrun downloads; it can exceed the startup timeout. - STDIO vs HTTP confusion. Server is built for one transport, you configured the other.
- Working directory mismatch. Server uses relative paths; Claude starts it from a different cwd than you tested.
Fix — run the server manually first
# Grab the exact command from .mcp.json
cat .mcp.json | jq '.mcpServers["<server-name>"]'
# Run it yourself, in the same shell you start `claude` from
npx -y @modelcontextprotocol/server-postgres postgresql://localhost:5432/dev
If the manual run prints errors, fix those — Claude was swallowing them. If the manual run works but Claude still fails:
claude mcp list # see status
claude mcp test <name> # invoke a no-op call (if supported in your version)
Common env-var fix
{
"mcpServers": {
"linear": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-linear"],
"env": {
"LINEAR_API_KEY": "${env:LINEAR_API_KEY}"
}
}
}
}
Make sure LINEAR_API_KEY is exported in your shell before running claude. .env files loaded by your app are not automatically visible to Claude.
Prevention
When you add a new MCP server, always test it in a scratch shell before wiring it in. The 10 seconds of npx -y <server> saves 20 minutes of "why isn't this working."
Tokens Exploding
Symptom — /cost shows a number that makes you wince. Your monthly bill is 3× what you expected. A single feature cost more than a whole week should.
Likely causes
.gitignoredoesn't cover your stack's build outputs. Claude respects gitignore for searches, so anything gitignored is already hidden — but ifdist/,.next/, or a language-specific cache isn't gitignored, Claude reads it. Tens of thousands of wasted tokens per session.CLAUDE.mdis 15K tokens. It loads every session, so every session pays the tax before you've typed anything.- Tool loop. Claude called the same thing 40 times because each result pointed back to the same missing dependency.
- Huge file reads. A single
Readon a 5K-line file is 15K tokens. Multiply by 10 reads. - Runaway subagents. Subagents doing deep exploration with no budget.
- Sonnet/Opus for work Haiku could do. Routing decisions compound — see Tokens → Model Routing.
Fix — the 5-minute audit
/context # see the breakdown — system prompt, CLAUDE.md, tools, files, convo
/cost # total tokens used this session + $ spent
Look at /context:
- System + tools > 50K → you have too many MCP servers loaded or too many hooks.
- CLAUDE.md > 5K → put it on a diet. See Tokens → CLAUDE.md Diet.
- Conversation > 100K → you're in a marathon session; hand off per Workflows → Context Handoff.
- Files > 30K and you didn't ask for that → a path Claude read that should've been gitignored, or a large committed file that needs
Read(...)denied.
The three highest-leverage fixes
- Audit your
.gitignore. Make surenode_modules/,dist/, build artifacts, and.cache/are in it. Claude respects it for searches, and that recovers 20–40K tokens in most repos. For committed-but-oversized paths, add aRead(./path/**)topermissions.deny. - Halve your
CLAUDE.md. Every token there pays interest on every session. - Route routine tasks to Haiku. Subagents especially.
See Tokens → The 3 Fixes for the full version.
The 24-hour rule
If a CLAUDE.md entry hasn't saved you from a mistake in the last 24 hours of work, it's probably not worth its tokens. Audit quarterly.
Rate Limits
Symptom — 429 errors, "please slow down" messages, or requests hanging and then failing. Happens most often when multiple parallel agents fire at once.
Likely causes
- Your plan's per-minute or daily limit. Pro / Team / Enterprise all have different caps. Team accounts are pooled.
- Burst parallelism. Three worktrees firing Best-of-N simultaneously → nine concurrent Claude calls → 429.
- An MCP or hook is hammering the API. Not you directly — a hook that calls Claude on every file edit.
- Model tier. Opus has stricter per-minute caps than Sonnet or Haiku.
Fix — in order
# The dashboard is the source of truth
open https://console.anthropic.com/usage
Then, depending on cause:
- Parallel agents burst → serialize them. Run three agents in sequence via a shell loop instead of three terminals at once.
- One Opus agent → drop it to Sonnet. Most work doesn't need Opus.
- Recurring hook → check if the hook is calling Claude. If so, either disable it during intensive sessions or give it its own lower-tier model.
Programmatic backoff
If you're driving Claude via the SDK or a script, implement exponential backoff — not a tight retry loop, which just makes the 429 worse.
import time, random
for attempt in range(5):
try:
return client.messages.create(...)
except anthropic.RateLimitError:
wait = (2 ** attempt) + random.random()
time.sleep(wait)
raise RuntimeError("rate limited 5× in a row")
Prevention
If you're running agent teams, put a concurrency cap on the orchestrator: no more than N parallel agents at once, where N is the sustainable limit for your plan. Two is fine for most plans; five is where things get tight; ten and you'll burn through limits inside an hour.
Auth & Login Issues
Symptom — 401 unauthorized, "token expired," login redirect loop in the browser, or claude starts but can't call the model.
Likely causes
- OAuth token expired. Most common for users on the Pro/Team plans.
- Stale API key. Rotated on the dashboard,
.envor shell not updated. - Two auth sources conflicting.
ANTHROPIC_API_KEYin your env and an OAuth session — Claude picks one, and it might be the wrong one. - Wrong account. You logged into the personal account; the repo expects the work account.
- Corporate VPN / proxy. Blocks the OAuth redirect or the API calls.
Fix — the reset sequence
claude /logout # clears the cached OAuth token
# clear any stale env vars in the current shell
unset ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN
claude /login # fresh browser auth
If you're using an API key (not OAuth):
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5-20251001","max_tokens":10,"messages":[{"role":"user","content":"ping"}]}'
- 200 OK → key works. The problem is in your
claudeconfig, not the key. - 401 → key is wrong or rotated. Generate a fresh one in the console.
- 403 → key is right, but your account/plan doesn't allow that model.
When two auth sources conflict
Check what's set:
env | grep -i anthropic
If both ANTHROPIC_API_KEY and an OAuth session exist, claude typically prefers the API key. If you want OAuth to win, unset ANTHROPIC_API_KEY — or explicitly tell Claude which auth mode to use via its config.
Corporate networks
If the browser-based login never redirects back, you're likely behind a proxy stripping the OAuth callback. Workarounds:
- Use an API key instead of OAuth (bypasses the redirect entirely).
- Add
api.anthropic.comandclaude.aito your proxy allowlist. - Authenticate from a non-corporate network once, then move back — tokens persist locally.
If none of the above fixes it
claude doctor dumps the full diagnostic: which auth source is active, which config files are loaded, which env vars are set, what version of Claude Code you're on. Run it first when in doubt — it's faster than guessing.