Troubleshoot a Claude Code session
Troubleshooting a Claude Code session means finding which layer failed before retrying: the configuration (settings, permission rules, CLAUDE.md, MCP servers, hooks), the conversation (stale or overloaded context), or the output (an over-built or wrong diff). Claude Code ships a diagnostic for each layer, and a fix counts only when the repository’s own checks pass again afterwards.
This page is for developers who run Claude Code every day and for the tech lead who owns the team’s shared .claude/settings.json. You wrote a deny rule and Claude still ran the command. Or the model ignores the convention that is plainly in CLAUDE.md, the Sentry MCP server shows no tools, and the last diff turned a 20-line service into a factory with three interfaces. Retrying the same prompt harder fixes none of these.
If you are new to Claude Code and need the basics of undoing an edit, start with error recovery. For install, login and error-message problems across all tools, see the troubleshooting guide.
What a working Claude Code troubleshooting routine gives you
Section titled “What a working Claude Code troubleshooting routine gives you”- A five-command triage that tells you which layer broke before you touch anything
- The permission-rule facts that explain why a rule “doesn’t work”, with a policy you can paste
- The right key for each kind of interruption (Esc, Enter to queue, Ctrl+C) and what each one keeps
- Four copy-paste prompts: triage, rule audit, de-overengineering, and proving the recovery
- A symptom-by-symptom recovery table for the failures you will actually hit
Which layer broke? Triage in five commands
Section titled “Which layer broke? Triage in five commands”Run these before you change a prompt or a setting. Each command answers one question, and together they take less than a minute.
| Question | Where you run it | Command | What to look for |
|---|---|---|---|
| Is the installation healthy? | Terminal | claude doctor | Installation health and problems in the settings files it reads |
| Which rules and modes are active? | Session | /permissions | Each rule and the settings file it comes from; the Recently denied tab for auto mode blocks |
| Which instructions loaded? | Session | /memory | The CLAUDE.md files in play and auto memory entries |
| Is context the problem? | Session | /context | A full grid, memory bloat, context-heavy tools |
| Are tools and hooks connected? | Session | /mcp, /hooks | Disconnected or unauthenticated servers; hooks on the event you expect |
claude doctor is the read-only terminal check; /doctor inside a session runs a fuller checkup that can also fix what it finds. claude --version matters too: Claude Code ships on a latest and a stable channel, and stable runs about a week behind, so a feature this page describes may not exist on your install yet (checked against v2.1.283, 2026-09-26).
When the triage points at your configuration but you can’t tell which piece, bisect it:
# Terminal: start with CLAUDE.md, skills, plugins, hooks and MCP servers all disabled.# Managed (policy) settings, auth, model and permissions still apply.claude --safe-mode
# If the problem disappears, it lives in your customizations. Turn on debug logging# for just the categories you suspect and write it to a file you can read afterwards.claude --debug "api,hooks" --debug-file /tmp/claude-debug.logInside a running session, the bundled /debug skill turns on debug logging and reads the session log for you.
Why doesn’t my permission rule take effect?
Section titled “Why doesn’t my permission rule take effect?”Most “Claude ignored my rule” reports come down to four facts from the permissions reference (checked 2026-09-26, v2.1.283):
- Order is deny, then ask, then allow, and specificity does not change it. A broad
Bash(aws *)deny blocksaws s3 lseven if you also allowBash(aws s3 ls). A matching ask rule prompts even when a narrower allow rule matches. - Scopes combine; they don’t override. A deny in your user settings blocks a project-level allow, and the reverse. Managed settings beat everything, including command-line flags.
- The model does not enforce rules; Claude Code does. Writing “never run migrations” in
CLAUDE.mdshapes what Claude tries. It blocks nothing. Put the block inpermissions.denyor aPreToolUsehook. - The space before a trailing
*is part of the rule.Bash(ls *)matcheslsandls -labut notlsof;Bash(ls*)matcheslsoftoo. The legacyBash(ls:*)suffix means the same asBash(ls *), but a colon anywhere else is a literal character.
Two gotchas cost teams the most. First, a Read(./.env) deny covers Claude’s file tools, Bash file commands such as cat, head and sed, and redirections, but not a command that reads the file without naming it (grep -r API_KEY .) or a script that opens it (node -e …, python …). Keep secrets out of the working tree or turn on sandboxed Bash; see permissions and sandboxes. Second, path rules are checked only for Read(...) and Edit(...): a rule written as Write(docs/**) is accepted and never consulted, and Claude Code warns about it at startup.
A starting policy for .claude/settings.json that you can commit for the team:
{ "permissions": { "allow": [ "Bash(git status)", "Bash(git diff *)", "Bash(npm test *)", "Bash(npm run lint *)" ], "ask": [ "Bash(git push *)", "Bash(npm install *)", "Bash(git clean *)" ], "deny": [ "Bash(git push --force *)", "Bash(git push -f *)", "Bash(rm -rf *)", "Read(./.env)", "Read(./secrets/**)" ] }}A Bash deny rule matches the spelling Claude usually writes, not the program: rm -fr or git push origin +main slip past these rules, so pair them with sandboxed Bash or a PreToolUse hook for anything that must never happen.
Deny and ask rules match any subcommand, including one nested in cd /tmp && git clean -f or a $( … ) substitution, so git clean prompts even in auto mode. SQL such as DROP TABLE is not a Bash command: gate destructive database operations in the MCP server’s own configuration or behind an ask rule on the tool that runs them.
From v2.1.283 (the latest channel), auto mode is the starting mode for interactive terminal and VS Code sessions: a classifier reviews actions instead of prompting you. Sessions started with claude -p or the Agent SDK, sessions whose settings disable auto mode, and sessions on a model auto mode does not support start in Manual instead. If the classifier blocked an action you expected to run, open /permissions, find it on the Recently denied tab, and press r to retry it with a manual approval. After 3 blocks in a row or 20 in one session, auto mode pauses and Claude Code prompts you again until you approve an action; those thresholds are not configurable. Note that auto or bypassPermissions as defaultMode in project settings is ignored; set it in user or managed settings.
Why is Claude ignoring my CLAUDE.md?
Section titled “Why is Claude ignoring my CLAUDE.md?”Check /memory first. Three causes cover most cases:
- The file isn’t loaded. Claude Code reads
AGENTS.mdonly when a project has noCLAUDE.md, and only from v2.1.277 on thelatestchannel (v2.1.281 on Bedrock, Google Cloud, Foundry, LLM gateways and telemetry-off installs). A repository with both getsCLAUDE.mdalone. - The instruction is buried. A 600-line
CLAUDE.mdcompetes with everything else in context. Move the rule that keeps being missed to the top, or into a hook if it must never be broken. See the memory system. - The rule was compacted or cleared. After a long session,
/compactsummarises the conversation, and a constraint you gave in chat (not inCLAUDE.md) may not survive. Put durable rules in the file, not in the conversation.
How to stop Claude without losing the session
Section titled “How to stop Claude without losing the session”The old advice “never press Ctrl+C, it kills the session” is wrong. Per the interactive mode reference (checked 2026-09-26):
| Key | While Claude is working | While idle |
|---|---|---|
Esc | Stops the response or tool call mid-turn; the work done so far stays | Closes a dialog |
Type, then Enter | Queues your message; Claude gets it as soon as the current tool calls finish, in the same turn | Sends the message |
Esc Esc | — | With text in the input: clears it (press Up to recall it from history). With empty input: opens the rewind menu |
Ctrl+Enter | Sends queued messages now instead of waiting (v2.1.275 or later; Ctrl+X Ctrl+S in terminals that do not report extended keys) | — |
Ctrl+C | Interrupts the running operation | First press clears the input, a second press exits Claude Code |
Choose by what you want to keep:
- Claude is on the right track but missing a constraint. Type it and press Enter. The message is queued, not an interruption: “Keep the v1 response shape; mobile clients still call it.” A queued message that joins the running turn gets no checkpoint of its own, so rewinding it means rewinding the whole turn. Changed your mind before Claude reads it? Press Up on the first line of the input to take queued messages back into the input box.
- Claude is heading the wrong way. Press Esc, then state the correction. The edits so far remain on disk, so check
/diffbefore you continue. - The whole approach is wrong. Press Esc, then Esc Esc on an empty prompt to rewind code and conversation to a point before the attempt. The error recovery guide covers the rewind menu in depth.
- You want to ask something without steering the work. Use
/btw: it answers a side question without adding it to the conversation.
How to make a failed Claude Code attempt cheap to undo
Section titled “How to make a failed Claude Code attempt cheap to undo”Checkpoints undo edits made by Claude’s file tools, but not files changed by Bash commands (rm, mv, a code generator) or by subagents (anything other than a foreground forked skill, including a background /code-review --fix run), and their snapshots are cleaned up after about 30 days by default. Git is the checkpoint that covers everything. The loop that keeps a bad attempt cheap:
-
Commit the current state before any change that touches more than one file.
Terminal window git add -p && git commit -m "checkpoint: before extracting billing adapter"git add -pstages by hunk, so a stray.envor build artifact does not ride along. -
Delegate the change with its acceptance check in the prompt: “Done means
npm testandnpm run typecheckpass and no file outsidesrc/billing/changes.” -
Judge the result by the check, not by reading. If the checks fail after two attempts, or
git diff --statshows files you didn’t expect, stop fixing forward. -
Reset and re-prompt with what you learned.
Terminal window git reset --hard HEAD # discards every uncommitted change, including your ownThen run
/clearand send a tighter prompt that names the constraint the first attempt missed.
Two failed fix attempts is the signal. A third attempt usually builds on the first two mistakes, and the context now holds all three.
What to do when Claude over-builds the solution
Section titled “What to do when Claude over-builds the solution”Over-building has a recognisable shape: a factory or registry with one product, an interface with one implementer, a configuration option nobody asked for, a new dependency for a ten-line job. git diff --stat shows it before you read a line: the file count and line count are out of proportion to the request.
Prevent the next one by adding a rule to CLAUDE.md that the model can act on, not a slogan:
## Scope rules- Add an abstraction only when there are two real callers today.- No new dependency without asking first.- If a change touches more than 5 files, stop and propose a plan before editing.Plan mode (/plan) does the same job for a single risky task: Claude explores and proposes without editing your source files, and you approve the plan before any change lands.
How to prove the recovered work is sound
Section titled “How to prove the recovered work is sound”A recovery is finished when the evidence says so, not when the diff looks plausible. Check in this order, cheapest first:
- Blast radius.
git diff --statand/diff: only the files the task named changed. - Gates. The repository’s one-command check (tests, typecheck, lint) passes locally. If the repository has no such command, that is the first thing to fix; see preparing an agent-ready codebase.
- Independent review.
/code-reviewreviews the current diff for correctness bugs as a separate pass, which catches what the session that wrote the code talked itself into. - Sign-off. You sign off on the evidence. Read the code itself only for the change classes your team reserves for human reading, as set out in reading evidence instead of code.
When a Claude Code session goes sideways: symptoms and fixes
Section titled “When a Claude Code session goes sideways: symptoms and fixes”| Symptom | Likely cause | Recovery |
|---|---|---|
| A denied command still ran | Rule written for the wrong tool (Write/Glob path rule) or without the space before *; the command reached the file without naming it (grep -r, a script), or used a different spelling (rm -fr vs rm -rf) | Run the rule-audit prompt; move secrets out of the tree or turn on sandboxed Bash |
| An allowed command still prompts | A broader ask or deny rule in another scope | /permissions shows each rule’s source file; remove or narrow the broader rule |
| Answers drift or repeat old mistakes | Context full of failed attempts | /context to confirm, then /compact with a focus (“keep only the billing refactor decisions”) or /clear and restart |
/clear removed something you needed | Cleared too early | /rewind can restore the conversation from before /clear in the same process; /resume picks the earlier session |
| An MCP server shows no tools | A .mcp.json server awaiting approval, or expired OAuth | claude mcp list marks pending servers; /mcp to approve or re-authenticate (or claude mcp login <name> from the terminal); /mcp reconnect <server>; see MCP setup |
| A hook never fires | Wrong event name or matcher; a hook error | /hooks to see what is registered; claude --debug "hooks"; see hooks automation |
Autocompact is thrashing: the context refilled to the limit... | One file or tool output refills the window right after each compaction | Ask for the file by line range or function, /compact keep only the plan and the diff, or move the large-file work to a subagent |
| Auto mode suddenly prompts for everything | The classifier blocked 3 actions in a row or 20 in the session, so auto mode paused | Check the Recently denied tab in /permissions; approve the next safe action to resume auto mode, or narrow the task |
| The session freezes and ignores keys | A hung tool call or terminal | Ctrl+C; if that fails, close the terminal and run claude --continue in the same directory (or claude --resume to pick a session): the conversation is kept |
| Usage limit hit mid-task | Long sessions at high effort | /usage for session cost and plan limits; lower /effort before switching model; see cost control |
| The same fix fails twice | Fixing forward on a wrong premise | Stop, git reset --hard to your checkpoint, /clear, re-prompt with the missed constraint |
On models: Claude Opus 5.5 is the default in Claude Code on the latest channel and runs at medium effort. When a hard task stalls, raise effort with /effort high before you change model, and move routine work to Claude Sonnet 5 only when cost dominates. Current prices and limits live on the models hub.
Where to go next after troubleshooting Claude Code
Section titled “Where to go next after troubleshooting Claude Code”- Make the fixes stick for the whole team: team collaboration covers shared settings,
CLAUDE.mdand review defaults. - Compare permission modes and sandboxes with Codex and Cursor: permissions and sandboxes.
- Keep an eye on sessions over time: monitoring Claude Code and cost control.
- For bugs in your application rather than in the session: debugging with Claude Code.
- If you have found a bug in Claude Code itself, run
/feedbackin the session to report it to Anthropic, with the steps that reproduce it.