The Navigator · 8 min mission

Troubleshooting & FAQ

Diagnose the common failure modes fast — and know where answers live.

troubleshootingfaqhelpFact-checked 2026-06-13
On this page

Most "Claude Code is broken" moments are not bugs. They are one of a handful of predictable failure modes — a context window that filled up, a permission you never granted, a hook that silently never matched, an install on the wrong PATH, an MCP server that started but returned nothing. The fix is almost never to flail. It is to ask one question — where is this stuck? — and run the one command that answers it.

This guide is that diagnostic flow. It teaches you to read the symptom, jump to the right layer, and confirm what Claude Code actually loaded instead of guessing. Learn the five or six commands below and you will spend your time fixing problems instead of reproducing them.

Start with the one-command triage

When something is wrong and you are not sure where, run /doctor inside Claude Code. It does an automated pass over your installation health, settings validity, MCP configuration, and context usage in a single check — so it tells you which layer is broken before you start digging. If claude won't even start, run claude doctor from your shell instead; same diagnostic, no session required.

/doctor is the triage nurse, not the surgeon. Its job is to point you at the right room. The rest of this guide is what you do once you are in it. Two diagnostic entry points cover almost everything: inside a running session, slash commands like /doctor, /context, /mcp, and /hooks are your instruments; if the session itself won't launch, the same tools have shell equivalents — claude doctor for health, and claude --debug mcp or claude --debug hooks to launch with verbose logging for one subsystem. When /doctor finds config errors, press f to hand the diagnostic report to Claude and have it walk you through the fix.

Context overflow: the most common "slowdown"

The complaint sounds like "Claude got dumber halfway through." Usually it didn't — the context window filled up. Every file read, command output, and message you exchange consumes the same finite budget, and when it runs low Claude Code automatically compacts: it summarizes the older conversation to reclaim space. A summary is lossier than the original, so detail you cared about can quietly fade.

Run /context to see exactly what is occupying the window right now, broken down by category: system prompt, memory files, skills, MCP tool definitions, and conversation history. That breakdown is the diagnosis. If MCP tools dominate, you have too many servers loaded; if conversation history dominates, it is time to reset.

The fixes are proactive, not heroic. Use /clear when you switch to unrelated work — stale context from the last task wastes tokens on every message that follows. Use /compact to summarize on demand, and steer what survives with an instruction: /compact keep only the plan and the diff. And write specific prompts: "add input validation to the login function in auth.ts" reads a couple of files, while "improve this codebase" triggers a broad scan that burns the window before any work happens.

Permission surprises: it stopped to ask, or it refused

Claude Code asks before it does anything consequential — running a command, writing a file, hitting the network — unless you have pre-approved that action. So two opposite surprises trace to the same place. "Why does it keep prompting me?" means the action isn't on your allow list. "Why won't it touch this file?" means a deny rule, or a missing allow rule, is blocking it.

The instrument here is /permissions, which shows the resolved allow and deny rules actually in effect after every settings scope has merged. That word resolved matters: rules come from managed, user, project, and local settings, and the closer scope wins. A value you set in settings.json can be silently overridden by the same key in settings.local.json, which a managed policy can override in turn. /permissions shows you the answer after all that merging, so you stop arguing with a rule you forgot you wrote.

One sharp edge worth internalizing: prefix deny rules match the literal command string, not the underlying program. A Bash(rm *) deny rule does not block /bin/rm or find . -delete, because those are different strings. For a real guarantee — not just a nudge — you reach for a PreToolUse hook or the sandbox, not a longer list of patterns.

Hooks that never fire: a silent matcher problem

Hooks are the opposite of chatty. When a hook doesn't run, nothing errors — it just quietly does nothing, which makes it the most confusing subsystem to debug by feel. Don't debug by feel. Run /hooks to list every hook registered for the session, grouped by event. If your hook isn't in that list, it was never read, and the cause is almost always location: hooks live under the "hooks" key inside settings.json, not in a standalone hooks file. (Only plugins use a separate hooks/hooks.json.)

If the hook does appear in /hooks but still never runs, the matcher is the usual culprit. The matcher field is a single string, and matching is case-sensitive against capitalized tool names — Bash, Edit, Write, Read. A lowercase "bash" or a misspelled tool name fails silently because the matcher simply never matches. To match several tools, use one string joined with |, like "Edit|Write" — writing matcher as a JSON array is a schema error, and /doctor will flag it.

When /hooks shows the hook but it still won't fire, watch evaluation live: launch with claude --debug hooks and trigger the tool call. The debug log records each event, which matchers were checked, and the hook's exit code and output — the exact place the chain is breaking.

isolate the culprit with safe mode
… scroll to run this session
When you cannot tell whether a plugin, hook, MCP server, or memory file is the problem, --safe-mode launches with every customization disabled. If the issue vanishes, one of those surfaces is the cause.

Install and auth: "command not found" and the phantom API key

Two install-and-login problems account for most first-day pain.

command not found: claude after a successful install means the binary isn't on your PATH. The native installer places claude at ~/.local/bin/claude on macOS and Linux (or %USERPROFILE%\.local\bin\claude.exe on Windows). If that directory isn't in your shell's search path, your shell can't find it — add ~/.local/bin to your PATH in ~/.zshrc or ~/.bashrc and reopen the terminal. A related trap: the VS Code extension bundles its own private copy of the CLI and does not add claude to your PATH, so installing only the extension leaves claude missing from the terminal. Run the standalone install for terminal use. If an old npm install -g is throwing permission errors, the documented fix is to switch to the native installer (curl -fsSL https://claude.ai/install.sh | bash) rather than fighting npm's global directory.

"This organization has been disabled" despite an active subscription is the sneakiest auth bug, and it is rarely about your account. A leftover ANTHROPIC_API_KEY environment variable — often from a previous job or project still set in your shell profile — overrides your subscription's OAuth credentials, so Claude Code bills the dead key instead of your plan. Run /status to confirm which authentication method is actually active. The fix is to unset ANTHROPIC_API_KEY and delete the export line from ~/.zshrc, ~/.bashrc, or ~/.profile. For ordinary login hiccups — a loop, an expired token, an OAuth error — the reset is blunt and reliable: run /logout, close Claude Code, relaunch with claude, and sign in again.

MCP servers that won't connect

An MCP server can be configured perfectly and still hand you no tools, which is why "it's connected but doesn't work" is so common. Run /mcp to see every configured server, its connection status, and whether you have approved it for this project. Three failure shapes cover almost everything:

First, a project-scoped server in .mcp.json is waiting on a one-time approval. If you dismissed that prompt, the server stays disabled until you approve it from /mcp. Second, a server that fails to start shows as failed — and the usual reason is a relative path in its command or args, because that path resolves against the directory you launched Claude Code from, not the location of .mcp.json. Use absolute paths for local scripts; executables already on your PATH like npx or uvx work as-is. Third, a server that shows connected but lists zero tools started fine but isn't returning a tool list — select Reconnect from /mcp, and if the count stays at zero, run claude --debug mcp to read the server's stderr output and see why.

One configuration gotcha causes silent breakage: environment variables set in settings.json's env block do not propagate to MCP child processes. If a server needs an API key or token, set a per-server env inside .mcp.json itself.

Walk the diagnostic tree

Symptom → fix

Pick what you're seeing. A question or two later you land on the exact command to run — every step pulled straight from the Claude Code troubleshooting docs.

Where does it hurt?

Start from the symptom you actually see, follow the branches, and land on the one command that confirms the cause. This is the muscle memory the whole guide is teaching.
SymptomRun this firstWhat it reveals
Anything unclear — not sure where it broke/doctor (or claude doctor from the shell)Install health, settings validity, MCP config, and context usage in one pass
Responses degrade or "forget" detail mid-task/contextWhat is filling the window: memory, MCP tools, or conversation history
Keeps prompting, or refuses to touch a file/permissionsThe resolved allow/deny rules after all scopes merge
A hook never seems to run/hooks, then claude --debug hooksWhether the hook loaded, and which matchers were checked live
MCP server connected but gives no tools/mcp, then claude --debug mcpApproval status, start failures, and the server's stderr
Unsure which authentication is in use/statusThe active auth method and which settings sources are in effect
The symptom-to-instrument map. When something is wrong, jump to the row that matches and run the command — it tells you what actually loaded, instead of guessing.

Guessing vs. diagnosing

Flailing

A rule isn't applying, so you re-edit settings.json, restart the terminal, toggle the feature off and on, and re-edit again — never confirming whether the file even loaded or which scope is winning.

You are debugging blind, and every change adds a new variable.

Diagnosing

You run /doctor to find the broken layer, /permissions to see the resolved rules, and claude --safe-mode to confirm a customization is the cause.

Each command removes a guess. You change exactly one thing, because you know which thing.

Knowledge check

A teammate set an MCP server's API key under the `env` block in `settings.json`, but the server starts without it and every call fails. What is the actual fix?

When nothing works: where to get help

Four escalation paths, in order. Run /doctor once more — and if it surfaces config errors, press f to send the report to Claude and have it walk through fixes with you (claude doctor from the shell if claude won't launch). Report it with /feedback, the command inside Claude Code that sends a problem directly to Anthropic with your session context attached — the fastest path for a bug you can reproduce live. Check the claude-code GitHub repo for known issues before assuming you found a new one; many install and platform quirks are already tracked there with workarounds. And ask Claude directly — it has built-in access to its own documentation, so "how do I…" and "what does this flag do" questions get answered without leaving the terminal.

The distilled FAQ

Did I lose my conversation when it froze? No. If a command hangs, press Ctrl+C to cancel; if the terminal is fully stuck, close it and run claude --resume in the same directory to pick the session back up.

Why is @file mentions or search not finding files? The bundled ripgrep binary may not run on your system. Install your platform's ripgrep package (for example brew install ripgrep) and set USE_BUILTIN_RIPGREP=0 in your environment so Claude Code uses it instead.

My text looks garbled in the VS Code or Cursor integrated terminal. The terminal's GPU renderer is usually the cause. Run /terminal-setup inside Claude Code to turn off integrated-terminal GPU acceleration, then reload the window.

Is my CLAUDE.md instruction being ignored because the file didn't load, or because of how it's written? Run /memory to confirm it loaded. If it's in the list, the issue is the writing, not the loading — and remember that subdirectory CLAUDE.md files load on demand when Claude reads a file in that directory, not at session start. If it's not in the list, it's a location problem.

How do I rule out my own customizations entirely? Launch claude --safe-mode. It disables CLAUDE.md, skills, plugins, hooks, MCP servers, and custom commands while keeping auth, model selection, built-in tools, and permissions working. If the problem disappears, one of those surfaces is the cause — then use the targeted / commands above to find which.

Reach the end and this star joins your charted sky.