Skip to content

Troubleshooting

Common problems, their cause, and the one-line fix. Start with claude-coder doctor — it diagnoses most of these read-only, without spawning claude or spending anything.

Run doctor first

doctor runs three read-only checks. It exits 0 when every check is pass or warn, and 1 only when one is fail.

claude-coder doctor
✓ auth            subscription OAuth (no billed credential in force)
✓ config          no profiles file (built-ins only)
✓ git-hooks       no .githooks/pre-commit in this repo (nothing to activate)

✓ overall: pass

Each row below maps a doctor line (or a runtime error) to its cause and fix.

Doctor warnings and failures

auth — fail

Symptom: a billed credential / auth-redirect env var is in force (env var '<NAME>' is set). Cause: An explicit API key or provider redirect is set in your environment. claude-coder always drives the subscription via OAuth and rejects these. Fix: unset the named variable, then sign in with claude (/login). See auth failures below and security.

config — fail

Symptom: A config error message (not found, malformed, or a credential rejection). Cause: An explicit --config path is missing, the file is malformed JSON, or a profile sets a credential env var. Fix: Fix or remove the profiles file. A missing default file is fine — it is pass ("no profiles file (built-ins only)"). See no profiles file.

git-hooks — warn

Symptom: .githooks/pre-commit present but not activated (core.hooksPath unset), or core.hooksPath='<x>' — the pre-commit secret-leak guard is not active. Cause: A repo ships a .githooks/pre-commit secret-leak guard, but it is not wired up — the hook only fires once core.hooksPath=.githooks is set. A fresh clone that never ran npm install (which runs the prepare installer) silently has no local guard. Fix: Run npm install (its prepare step activates it), or set it directly: git config core.hooksPath .githooks. A repo without a .githooks/pre-commit is pass ("nothing to activate"). This check never fails — it is purely advisory.

Note

This is a pure read: doctor parses core.hooksPath from .git/config and never spawns git. It only surfaces the path value, never any other config (so a remote URL with an embedded token is never echoed).

unsupported_version

Symptom: A PTY session fails to start with claude --version "<v>" is not in the supported range [2.1.0, 2.2.0). Cause: The installed claude is below 2.1.0 or at/above 2.2.0. PTY keystroke safety is gated to this band. Fix: Install a claude whose claude --version lands in [2.1.0, 2.2.0).

Note

Any in-band 2.1.x patch is accepted — there is no exact pin. SDK profiles do not use the band and are unaffected.

Auth failures

Symptom: subscription OAuth required: an explicit API key / auth-redirect is in force ..., or a transport auth error refusing to drive the session. Cause: Auth is always the Claude subscription via OAuth, never an API key. Setting any of these is rejected:

Variable Why it is rejected
ANTHROPIC_API_KEY explicit API key — overrides subscription OAuth
ANTHROPIC_AUTH_TOKEN explicit auth token
ANTHROPIC_BASE_URL endpoint / billing redirect
AWS_BEARER_TOKEN_BEDROCK Bedrock bearer token
CLAUDE_CODE_USE_BEDROCK / _VERTEX / _FOUNDRY provider auth redirects

Fix: unset the offending variable, then sign in with the subscription:

unset ANTHROPIC_API_KEY   # or whichever doctor named
claude   # then run /login

The same deny set rejected here also blocks a profile that sets it — that is the credential_in_profile error below. See security.

credential_in_profile (config rejected)

Symptom: Config load fails because a profile's env (or settings.env) sets a credential variable. Cause: Profiles may not carry credentials — auth is OAuth-only. Fix: Remove the credential key from the profile. Use a secret reference for non-auth secrets your tooling needs, never an Anthropic auth key.

No profiles file

Symptom: doctor reports config no profiles file (built-ins only), and only claude-code-expert appears. Cause: No config file at the default path. This is normal — the built-in profile is always available. Fix (optional): Add profiles only if you need them. Create ./claude-coder.config.json (project-local) or ~/.claude/claude-coder/profiles.json (global):

[
  {
    "name": "my-pty",
    "transport": "pty",
    "cwd": "/home/user/code"
  }
]

Warning

A missing default path is silent (built-ins only). A missing explicit --config <path> is a hard error (exit 1). See profiles.

A PTY turn won't settle / trust dialog appears

Symptom: A PTY-backed turn hangs and never completes, often the first time you drive a folder. Cause: Usually one of:

  • The folder's trust dialog ("Yes, I trust this folder") is open and was not auto-accepted.
  • An ambient MCP server that needs auth is churning the welcome screen, defeating the idle detector.
  • The live TUI drifted from the certified grammar, so the wrapper latched keystroke injection off (fail-closed) and the turn stays observable but inert.

Fix:

  1. Confirm claude --version is in-band — a drifted or out-of-band TUI fails per-surface verification and no keystroke is sent.
  2. The wrapper already isolates the child with --strict-mcp-config, so user-global MCP should not load. If you injected an auth-needing MCP server via a profile, remove it.
  3. Re-run; if drift latched, restart the session. The fail-closed posture is intentional — it never sends a blind keystroke. See security.

Still stuck?

Re-run doctor --json for a machine-readable report, and confirm the basics: Node >= 22, claude signed in via /login, and claude --version in [2.1.0, 2.2.0) for PTY.

claude-coder doctor --json