CLAUDE_CONFIG_DIR set to the default path ($HOME/.claude) selects a different Keychain credential entry than leaving it unset, with no diagnosis

Status Open
Reported on v2.1.261
Maintainer reply None cached
Activity 0 comments · opened Sep 5, 2026

What's Wrong?

Per the docs (Authentication → Credential management), setting CLAUDE_CONFIG_DIR keys the macOS Keychain entry to that directory, "so a session with a different CLAUDE_CONFIG_DIR reads a different entry." That's expected when the directory actually differs. But here the directory is byte-identical to the default — only whether the variable is textually present differs — and the result is a full loss of login, with nothing in auth status or the "Not logged in · Please run /login" message saying which credential store was consulted.

Any script or automation that forwards CLAUDE_CONFIG_DIR unconditionally (e.g. to pin a relocated install's root, or because it defensively re-sets process.env values) silently breaks auth for that child process the moment the parent never had the variable set in the first place.

Steps to Reproduce

claude auth status
# → {"loggedIn": true, "authMethod": "claude.ai", ...}

CLAUDE_CONFIG_DIR="$HOME/.claude" claude auth status
# → {"loggedIn": false, "authMethod": "none"}

Variants that isolate it to the variable's literal presence/value, not path resolution:

CLAUDE_CONFIG_DIR="$HOME/.claude/" claude auth status                # trailing slash → still false
CLAUDE_SECURESTORAGE_CONFIG_DIR="$HOME/.claude" claude auth status   # → still false

(An unexpanded CLAUDE_CONFIG_DIR='~/.claude' also fails, but that's a genuinely different directory — auth status reports projectsDirectory: "~/.claude/projects", literal tilde, unresolved — so it isn't a same-directory data point and is omitted here.)

Workaround, pinning the default credential store explicitly — restores login but not identity reporting:

CLAUDE_CONFIG_DIR="$HOME/.claude" CLAUDE_SECURESTORAGE_CONFIG_DIR="" claude auth status
# → {"loggedIn": true, "authMethod": "claude.ai", "email": null, "orgId": null, "orgName": null, "subscriptionType": "max"}

Environment

  • claude --version: 2.1.261 (npm install under Homebrew's node prefix)
  • macOS 26.6.2 (arm64)
  • OAuth subscription login (Claude.ai, Max plan); ~/.claude/.credentials.json does not exist — Keychain-only credential store
  • Regression status: unknown, not tested on earlier versions (per #79223, the CLI has recognized CLAUDE_SECURESTORAGE_CONFIG_DIR since roughly 2.1.144, which is the related-but-separate mechanism this report's CLAUDE_CONFIG_DIR keying appears to route through — not a claim about when CLAUDE_CONFIG_DIR's own keying began)

What Should Happen?

Primarily: make this diagnosable. claude auth status and the --print "Not logged in" path should report which credential store/Keychain entry was consulted (and that an explicit CLAUDE_CONFIG_DIR selects a different one than unset), instead of an undifferentiated "Not logged in · Please run /login". This should also be documented alongside the existing CLAUDE_CONFIG_DIR docs, not only inferable from CLAUDE_SECURESTORAGE_CONFIG_DIR behavior.

Alternative (one clause): resolve an explicit CLAUDE_CONFIG_DIR that is byte-identical to the default to the same credential entry as leaving it unset. (This has a migration wrinkle — anyone who already logged in under the explicit path has a credential in the other slot — so the diagnosability fix above is the safer primary ask.)

Related

  • #87447 — "Repro C" in that issue is this same unset-vs-explicit-default discrepancy (seen there as loggedIn:true with null identity on Windows' plaintext credential file; here as a clean loggedIn:false on macOS Keychain). Buried as the third of three repros in a broader issue about a different primary complaint.
  • #79223 — documents CLAUDE_SECURESTORAGE_CONFIG_DIR behavior in detail, including "setting the variable to your default config directory's absolute path selects a different, empty credential store, which presents as a lost login" and "an empty value pins the default credential store." This issue's repro matches that description exactly; #79223 is a docs request for the sibling variable, not a report against CLAUDE_CONFIG_DIR's own behavior or the error message.
  • #88601 — describes per-config-dir credential isolation as current behavior (different directories get different Keychain items, Claude Code-credentials-<hash>); closed by its own author, not a maintainer statement of intent. Not in conflict with this report, which is about explicit-vs-unset for the same directory.
  • #84275 / #90527 — a different, adjacent defect (hash-suffixed Keychain items accumulating daily, never cleaned up), not this one.

Additional context

Found this while debugging a background automation that unconditionally forwarded CLAUDE_CONFIG_DIR to a spawned child process — even when the parent never had the variable set, the forwarding code still injected the resolved-to-default path, reproducing this exactly. Only forwarding the variable when the parent actually had it set resolved it.

View original on GitHub ↗