Skip to content

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.

QuestionWhere you run itCommandWhat to look for
Is the installation healthy?Terminalclaude doctorInstallation health and problems in the settings files it reads
Which rules and modes are active?Session/permissionsEach rule and the settings file it comes from; the Recently denied tab for auto mode blocks
Which instructions loaded?Session/memoryThe CLAUDE.md files in play and auto memory entries
Is context the problem?Session/contextA full grid, memory bloat, context-heavy tools
Are tools and hooks connected?Session/mcp, /hooksDisconnected 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 window
# 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.log

Inside 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):

  1. Order is deny, then ask, then allow, and specificity does not change it. A broad Bash(aws *) deny blocks aws s3 ls even if you also allow Bash(aws s3 ls). A matching ask rule prompts even when a narrower allow rule matches.
  2. 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.
  3. The model does not enforce rules; Claude Code does. Writing “never run migrations” in CLAUDE.md shapes what Claude tries. It blocks nothing. Put the block in permissions.deny or a PreToolUse hook.
  4. The space before a trailing * is part of the rule. Bash(ls *) matches ls and ls -la but not lsof; Bash(ls*) matches lsof too. The legacy Bash(ls:*) suffix means the same as Bash(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.

Check /memory first. Three causes cover most cases:

  • The file isn’t loaded. Claude Code reads AGENTS.md only when a project has no CLAUDE.md, and only from v2.1.277 on the latest channel (v2.1.281 on Bedrock, Google Cloud, Foundry, LLM gateways and telemetry-off installs). A repository with both gets CLAUDE.md alone.
  • The instruction is buried. A 600-line CLAUDE.md competes 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, /compact summarises the conversation, and a constraint you gave in chat (not in CLAUDE.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):

KeyWhile Claude is workingWhile idle
EscStops the response or tool call mid-turn; the work done so far staysCloses a dialog
Type, then EnterQueues your message; Claude gets it as soon as the current tool calls finish, in the same turnSends 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+EnterSends queued messages now instead of waiting (v2.1.275 or later; Ctrl+X Ctrl+S in terminals that do not report extended keys)—
Ctrl+CInterrupts the running operationFirst 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 /diff before 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:

  1. 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 -p stages by hunk, so a stray .env or build artifact does not ride along.

  2. Delegate the change with its acceptance check in the prompt: “Done means npm test and npm run typecheck pass and no file outside src/billing/ changes.”

  3. Judge the result by the check, not by reading. If the checks fail after two attempts, or git diff --stat shows files you didn’t expect, stop fixing forward.

  4. Reset and re-prompt with what you learned.

    Terminal window
    git reset --hard HEAD # discards every uncommitted change, including your own

    Then run /clear and 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.

A recovery is finished when the evidence says so, not when the diff looks plausible. Check in this order, cheapest first:

  1. Blast radius. git diff --stat and /diff: only the files the task named changed.
  2. 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.
  3. Independent review. /code-review reviews the current diff for correctness bugs as a separate pass, which catches what the session that wrote the code talked itself into.
  4. 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”
SymptomLikely causeRecovery
A denied command still ranRule 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 promptsA 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 mistakesContext 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 neededCleared too early/rewind can restore the conversation from before /clear in the same process; /resume picks the earlier session
An MCP server shows no toolsA .mcp.json server awaiting approval, or expired OAuthclaude 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 firesWrong 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 compactionAsk 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 everythingThe classifier blocked 3 actions in a row or 20 in the session, so auto mode pausedCheck the Recently denied tab in /permissions; approve the next safe action to resume auto mode, or narrow the task
The session freezes and ignores keysA hung tool call or terminalCtrl+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-taskLong sessions at high effort/usage for session cost and plan limits; lower /effort before switching model; see cost control
The same fix fails twiceFixing forward on a wrong premiseStop, 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”