Patterns, Anti-Patterns & Troubleshooting

Recognize the trap, apply the fix

Intermediate 13 minBuilder
What you'll be able to do
  • Recognize the common Claude Code failure patterns by their symptoms and name the root cause behind each
  • Apply the right fix — /clear, deny rules, hooks, fresh sessions, and config changes — instead of guessing or starting over
  • Diagnose auth, update, and context problems using claude doctor, /doctor, /debug, --debug, and /heapdump
  • Avoid the highest-blast-radius traps: bypassPermissions outside a sandbox, relying on checkpoints for bash file changes, and context-only /btw for investigation
  • Build the habits — git as the real safety net, /clear between tasks, deny rules for guarantees — that prevent these failures recurring
At a glance

When Claude Code starts behaving badly, it is almost always one of a handful of recurring failure patterns — and each one has a fast, concrete fix. This lesson is a playbook: it pairs every symptom with its root cause and the exact remedy, then arms you with the diagnostic commands (claude doctor, /doctor, /debug, --debug, /heapdump) so you can self-rescue instead of restarting blind.

  1. 1The mental model: symptom → root cause → fix
  2. 2Context patterns: the kitchen sink and the correction spiral
  3. 3When rules get ignored or boundaries get lost
  4. 4Broken sessions and the @-autocomplete gotcha
  5. 5Auth and update patterns: wrong account, stale binary
  6. 6Safety-net patterns: bypass, checkpoints, and context-only tools
  7. 7The diagnostic toolkit

The mental model: symptom → root cause → fix

Most Claude Code frustration is not random. It clusters into a small set of recurring failure patterns, and once you can name the pattern you already know the fix. The skill this lesson teaches is diagnosis: read the symptom, trace it to the root cause, apply the specific remedy — and stop reaching for the two reflexes that usually make things worse, restarting from scratch and arguing with Claude in conversation.

There is a structure under almost every failure. Claude Code is an agent driving a context window (a finite token budget that holds your conversation, files, and tool output) under a permission system, kept honest by git and checkpoints, and configured by CLAUDE.md, settings, and hooks. When something goes wrong, it is usually one of these four substrates straining:

SubstrateWhat strains itTypical symptom
Context windowMixed tasks, repeated reads, accumulated imagesConfused answers, ignored rules, 400 on resume
Instruction layerBloated CLAUDE.md, advisory-only rulesClaude ignores a rule it "agreed" to
Auth / installStale binary, key precedenceWrong account, no updates, login loops
Safety netBash edits, wrong mode, context-only toolsLost changes, can't undo, can't investigate

The rest of the lesson is a tour of the specific patterns inside each, paired with the exact command or config change that fixes it.

Key insight

The two reflexes to unlearn

When Claude misbehaves, the instinct is to (a) close everything and start over, or (b) keep correcting it in the same chat. Both usually deepen the hole — a fresh restart loses useful state, and repeated corrections bloat the very context that is causing the confusion. The right move is almost always a targeted command: /clear, a deny rule, a hook, or a diagnostic.

Context patterns: the kitchen sink and the correction spiral

The single most common failure is context pollution — the window fills with material that competes with the task at hand, and answer quality drops. Two patterns dominate.

The kitchen-sink session. You start a session to fix a bug, then — without clearing — pivot to a refactor, then ask about deploy config, then debug a test. Each unrelated task dumps files, logs, and tool output into the same window. By the fourth task Claude is reasoning over a soup of irrelevant context and starts conflating things. The fix is mechanical:

text
/clear   ← run this between unrelated tasks

/clear empties the context window for a clean slate (your prior conversation is still reachable via /resume). One coherent task per session keeps quality high. This is the antidote to the kitchen-sink anti-pattern.

The correction spiral. You ask for something, the result is wrong, so you correct it. Still wrong, correct again. Three corrections later you are deep in a thread where every turn references the previous mistake, and Claude is now anchored on the bad path. Piling on more corrections rarely recovers it — each one adds noise. The fix is to stop and restart the task with one better prompt:

text
/clear
# then a single, complete prompt that states the goal, the constraints,
# and what "done" looks like — instead of five patches to a bad first try

A clean window plus a well-specified single prompt almost always beats a long correction chain. If a task has gone three rounds without converging, that is your signal to reset rather than push.

Tip

Compact at ~60%, not 95%

For a long but coherent task you don't want to clear, run /compact [focus] to summarize older turns while keeping CLAUDE.md, skills, and memory. Do it manually around 60% full (check with /context) rather than waiting for auto-compaction near the limit — it's cheaper and produces a sharper summary.

When rules get ignored or boundaries get lost

Two failures look like Claude "disobeying" but have very different root causes — and different fixes.

Symptom: Claude ignores a CLAUDE.md rule. You wrote the rule, Claude read the file, and it still does the wrong thing. The usual root cause is that CLAUDE.md is too long. CLAUDE.md is delivered as context, not as a system prompt, so compliance is advisory — and a bloated file buries the important rule in noise until it gets lost. Two fixes, in order of strength:

  • Prune it. Target under ~200 lines. Every line should answer "would Claude make a mistake without this?" If Claude already does something correctly, delete the rule about it. Tighter files get followed better.
  • Convert it to a hook. If the behavior must be guaranteed (run the linter on save, block a forbidden pattern), move it out of advisory CLAUDE.md and into a hook — a shell command wired to a lifecycle event in settings.json. Hooks are deterministic; CLAUDE.md is a suggestion.

Symptom: a boundary you stated is lost after compaction. Early in a session you said "never push to main," and hours later — after a /compact — Claude pushes anyway. Root cause: spoken boundaries live in the context window, and compaction can summarize them away, silently, with no error. The fix is to encode the guarantee where it can't be dropped — a deny rule in settings.json:

json
{
  "permissions": {
    "deny": [
      "Bash(git push *)",
      "Bash(rm -rf *)"
    ]
  }
}

A deny rule is re-evaluated on every tool call and overrides the active permission mode, so it cannot be compacted away. The principle: advice goes in conversation/CLAUDE.md; hard guarantees go in deny rules.

Watch out

Compaction drops boundaries silently

Nothing errors when a spoken boundary is summarized away during compaction — Claude just proceeds as if you never said it, and by the time you notice, an irreversible action may be done. Match the enforcement strength to the cost of failure: if forgetting the rule would be expensive, it belongs in a deny rule or a hook, not a sentence.

Broken sessions and the @-autocomplete gotcha

Symptom: a session throws a 400 error on resume and won't recover. You /resume a session and immediately hit a persistent HTTP 400 — and it keeps happening. The usual culprit is image accumulation. Pasted images and screenshots are stored at full resolution inside the session's JSONL transcript; enough of them eventually push the request past a hard limit, producing permanent 400s on resume (this is the behavior behind issue #34025). Chrome MCP screenshots are an especially heavy offender for token drain (#27869). The fix:

  • Start fresh with /clear rather than fighting the broken transcript, and
  • Manage screenshots going forward — don't let visual artifacts pile up in one long session; /clear or /compact a session that has accumulated images before it breaks.

Symptom: an /add-dir file is missing from @ autocomplete. You added a directory with /add-dir (or --add-dir), but when you type @ to reference a file inside it, the file doesn't appear in the completion list. This is a known bug (#5605), not a configuration error on your end. The fix is simple: type the full path manually after @ instead of relying on Tab completion. (Related quirk: Tab completion doesn't expand ~, so spell out home paths too.)

Example

Recovering a 400-locked session

You resume a UI-debugging session that's full of pasted screenshots and get a 400 every time. Don't keep retrying /resume. Instead: start a new session with /clear, re-state the task in a few sentences, and paste back only the one or two images you actually still need. The session resumes cleanly because the request is no longer oversized.

Auth and update patterns: wrong account, stale binary

Two install-layer failures account for most "it's not working" reports.

Symptom: Claude is billing/acting on the wrong account — a Console API key is overriding your subscription. If ANTHROPIC_API_KEY is set, it takes precedence over your subscription OAuth login. So if you logged in with your Pro/Max plan but a stray ANTHROPIC_API_KEY lives in your shell profile, Claude Code quietly uses the Console key instead. The fix is to unset it so auth falls back to your subscription:

bash
unset ANTHROPIC_API_KEY     # current shell
# and remove it from ~/.zshrc / ~/.bashrc if it's written there

As a rule, don't write ANTHROPIC_API_KEY to your shell profile — it exposes the key to every child process and causes exactly this precedence surprise.

Symptom: Claude Code isn't updating to the latest version. Native installs auto-update in the background, but Homebrew, WinGet, and Linux package managers do NOT — they only move when you tell them to. If claude --version is stuck, run the manual upgrade for your installer:

InstallerManual upgrade command
Homebrew (cask)brew upgrade claude-code
WinGetwinget upgrade Anthropic.ClaudeCode
npmnpm install -g @anthropic-ai/claude-code@latest
Native (forced)claude update

Run claude doctor to see the last update attempt and confirm which install method you're on.

Note

WinGet upgrade fails while Claude Code is running

On Windows, winget upgrade can fail with a file lock if Claude Code is still running. Fully exit every Claude Code session first, then run the upgrade. The auth precedence rule also has a headless edge: in -p/print mode, ANTHROPIC_API_KEY is always used if present — another reason to keep it out of your profile.

Safety-net patterns: bypass, checkpoints, and context-only tools

These are the highest-blast-radius traps — the ones where the wrong assumption costs you real work or real safety.

bypassPermissions is for isolated containers only. --dangerously-skip-permissions (= bypassPermissions mode) disables every permission check — with one narrow circuit breaker: per the official permission-modes docs, removals targeting the filesystem root (/) or your home directory (~), like rm -rf / or rm -rf ~, still prompt as a safeguard against accidental model error. Everything else runs without asking. It exists for sandboxed containers and disposable VMs — ideally without network access — where there is nothing valuable to wreck. Running it in a real working directory means Claude can edit anything, run anything, and delete almost anything without asking. The flag name is the warning.

Checkpoints do NOT cover bash file changes — git does. Claude Code snapshots every file edit it makes through its own edit tools, so Esc Esc / /rewind can restore those. But changes made by bash commandsrm, mv, git reset --hard — are not checkpointed. If Claude (or a script it ran) deletes a file via the shell, rewind won't bring it back. The real safety net for shell-level changes is git: commit often so you always have a restore point that doesn't depend on the checkpoint system. (Checkpoints are also local to the session and separate from git, and cover file changes only — not database or API side effects.)

/btw can't investigate — it's context-only. /btw <question> answers a side question from the existing context without bloating your history — but it has no tool access. It can't read new files, run commands, or search the codebase. If your side question actually needs investigation ("is this function called anywhere?"), /btw will answer from memory and may be wrong. Use a subagent instead: it runs in isolated context with tools, does the real investigation, and reports a summary back without polluting your main thread.

Watch out

Git is the only real undo for shell changes

The most dangerous assumption is that /rewind can undo anything Claude did. It can't undo bash-level file operations (rm, mv, git reset), and it can't undo external side effects (a dropped table, a sent API call). Treat checkpoints as a convenience for tool-edits and lean on git commits as your durable safety net.

The diagnostic toolkit

When a symptom doesn't map cleanly to a known pattern, reach for the built-in diagnostics. Each answers a different question.

ToolWhereWhat it's for
claude doctorshellInstall & config diagnostics; shows the last update attempt and your install method
/doctorin-sessionSame health check inside a session — press f to auto-fix detected issues
/debug [desc]in-sessionOpen the in-session debug helper; optionally describe the problem
--debug "api,hooks"launch flagVerbose debug logging filtered by category (prefix ! to exclude a category, e.g. --debug "!statsig")
--debug-file /tmp/c.loglaunch flagWrite those debug logs to a file (implies --debug)
/heapdumpin-sessionDump memory heap for diagnosing leaks / runaway memory

A practical order of operations:

  1. Start with claude doctor (or /doctor, then f to fix) — it catches the majority of install/auth/update problems and can repair them.
  2. If behavior is wrong, not broken, relaunch with --debug scoped to the relevant category (api, hooks, ...) and read the trace; add --debug-file to capture it.
  3. For memory/performance issues, /heapdump.
bash
claude doctor                    # quick health + last update attempt
claude --debug "api,hooks"       # trace API + hook activity
claude --debug "!statsig" --debug-file /tmp/cc.log   # everything except statsig, to a file

One transient message deserves a special note: in auto mode, "cannot determine safety" is not a verdict or a failure — it's a transient hiccup in the background safety classifier. Don't change your config over it; just retry.

Tip

doctor first, debug second

Resist jumping straight to --debug log spelunking. claude doctor / /doctor (with f to fix) resolves the common install, auth, and update issues in seconds and tells you which install method you're on — information you'll need anyway. Save --debug and /heapdump for problems that survive a clean doctor run.

Try it: Run the troubleshooting playbook end to end

Practice the symptom → root cause → fix loop on a repo you actually work in. The goal is to cause each pattern deliberately, then fix it the right way.

  1. Health check first. Run claude doctor and read the output: which install method are you on, and when was the last update attempt? If you're on Homebrew/WinGet/a Linux package manager, run the matching manual upgrade (brew upgrade claude-code / winget upgrade Anthropic.ClaudeCode) and re-check claude --version.
  2. Provoke the kitchen sink. In one session, do three unrelated things (summarize a file, ask a deploy question, debug a test). Notice the context filling via /context. Then /clear and feel the difference — confirm prior history is still reachable via /resume.
  3. Make a rule stick. Add a vague, bloated rule to CLAUDE.md and observe it being ignored; then prune CLAUDE.md toward <~200 lines so the important rule is followed. For something that must be guaranteed, add a deny rule (e.g. Bash(git push *)) to .claude/settings.json and verify it blocks the action regardless of mode — even after a /compact.
  4. Trigger the @-autocomplete bug. /add-dir a sibling directory, then type @ and confirm its files don't appear in completion (#5605). Reference a file by typing the full path manually and confirm it loads.
  5. Prove the safety net. With git clean, have Claude run a bash rm on a throwaway file, then press Esc Esc and confirm rewind does not restore it. Recover it with git checkout instead — internalizing that git, not checkpoints, covers shell changes.
  6. Diagnose on purpose. Relaunch with claude --debug "api,hooks" --debug-file /tmp/cc.log, do one action, and skim the log to see the category-filtered trace. Then write a two-line note for each pattern above: the symptom, and the exact command that fixed it — that note is your personal troubleshooting cheat sheet.

Key takeaways

  1. 1Diagnose by pattern: read the symptom, trace it to context / instructions / auth-install / safety-net, then apply the specific fix — don't reflexively restart or pile on corrections.
  2. 2Context hygiene fixes the most common failures: `/clear` between unrelated tasks (kitchen-sink), and reset with one better prompt instead of a correction spiral.
  3. 3A rule ignored usually means CLAUDE.md is too long (prune to <~200 lines) or needs to be a hook; a boundary lost after compaction needs a deny rule, which survives compaction and overrides the mode.
  4. 4A 400 on resume is usually image accumulation — start fresh with `/clear` and manage screenshots; an `/add-dir` file missing from `@` autocomplete is bug #5605, so type the full path.
  5. 5Unset `ANTHROPIC_API_KEY` so a Console key stops overriding your subscription; Homebrew/WinGet/Linux installs need a manual `brew upgrade`/`winget upgrade` to update.
  6. 6Mind the safety net: `bypassPermissions` only in isolated containers, rely on git (not checkpoints) for bash file changes, and use a subagent (not context-only `/btw`) when a question needs investigation. Diagnose with `claude doctor`, `/doctor` (`f`=fix), `/debug`, `--debug`, `/heapdump`.

Quiz

Lock in what you learned

Check your understanding

0 / 4 answered

1.Halfway through a session you've fixed a bug, refactored a module, and asked about deploy config — and now Claude's answers are getting muddled and it's conflating the tasks. What's the root cause and the fix?

2.You told Claude at the start of a session 'never push to main.' Two hours and a /compact later, it pushes anyway. Why, and what's the robust fix?

3.Claude ran a shell command that deleted a file you needed (rm via Bash). You press Esc Esc to rewind — but the file doesn't come back. Why, and what should you have relied on?

4.Your side question is 'is this helper function called anywhere else in the codebase?' You ask it with /btw and get a confident answer that turns out to be wrong. What happened, and what should you use instead?

Go deeper

Hand-picked sources to keep learning