CLAUDE_CONFIG_DIR set to the default path ($HOME/.claude) selects a different Keychain credential entry than leaving it unset, with no diagnosis
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.jsondoes not exist — Keychain-only credential store - Regression status: unknown, not tested on earlier versions (per #79223, the CLI has recognized
CLAUDE_SECURESTORAGE_CONFIG_DIRsince roughly 2.1.144, which is the related-but-separate mechanism this report'sCLAUDE_CONFIG_DIRkeying appears to route through — not a claim about whenCLAUDE_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:truewith null identity on Windows' plaintext credential file; here as a cleanloggedIn:falseon macOS Keychain). Buried as the third of three repros in a broader issue about a different primary complaint. - #79223 — documents
CLAUDE_SECURESTORAGE_CONFIG_DIRbehavior 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 againstCLAUDE_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.