claude plugin install silently strips fields from .claude.json
Summary
claude plugin install <name> rewrites ~/.claude/.claude.json using a deserialize-modify-serialize cycle that silently drops any field outside the CLI's internal struct. Re-running it (even with a plugin that is already installed) shrinks the file from ~75 KB / ~60 keys to ~1.5 KB / 8 keys.
The dropped fields include subscription state, causing Claude Code to prompt for OAuth re-authentication on every session even though credentials in .credentials.json are intact.
Reproduction
- Healthy state:
wc -c ~/.claude/.claude.json→ ~75 KB claude plugin install <any-already-installed-plugin>(exits 0, no warning)wc -c ~/.claude/.claude.json→ ~1.5 KB
Observed vs expected
Lost fields include:
oauthAccount.organizationType(e.g."claude_max")oauthAccount.organizationRateLimitTier(e.g."default_claude_max_5x")projects.*per-project state map (entire map dropped)- ~50 onboarding / UI flags
- All install metadata not present in the CLI's plugin struct
Effect: without organizationType, the CLI treats the account as un-subscribed and re-prompts for OAuth on next session, despite valid accessToken / refreshToken in .credentials.json.
Expected: unknown fields should round-trip through claude plugin install untouched (standard pattern: deserialize into a typed struct + retain unknown fields, or operate at the JSON-value level).
Scope
- Confirmed:
claude plugin install - Likely (untested): any
claudeCLI subcommand that writes to.claude.json—mcp add,mcp remove,plugin uninstall, etc. The bug is in the read/write layer, not the install path.
Workaround
Backups under ~/.claude/backups/.claude.json.backup.<epoch_ms> preserve the pre-truncation state and allow full recovery via cp.
Idempotence guard in automation that calls the CLI: cache claude plugin list once, skip already-installed plugins. Avoids re-triggering the write entirely.
Suggested fix
Either (a) deserialize into a struct that preserves unknown fields (Go: use json.RawMessage for the catch-all; Rust: #[serde(flatten)] extra: Map<...>), or (b) operate at the JSON-value level (load → mutate one key → save) without round-tripping through a typed schema.
Version
claude --version: 2.1.144 (Claude Code)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗