claude plugin install silently strips fields from .claude.json

Status Fixed / completed
Reported on v2.1.144
Maintainer reply None cached
Activity 3 comments · opened May 19, 2026 · closed May 19, 2026

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

  1. Healthy state: wc -c ~/.claude/.claude.json → ~75 KB
  2. claude plugin install <any-already-installed-plugin> (exits 0, no warning)
  3. 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 claude CLI 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)

View original on GitHub ↗

3 Comments

github-actions[bot] · 5 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/59870
  2. https://github.com/anthropics/claude-code/issues/60380
  3. https://github.com/anthropics/claude-code/issues/16143

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

mlorentedev · 5 months ago

Closing as duplicate of #59870 — same root cause (CLI does not round-trip unknown fields on JSON writes) manifesting in a different file (.claude.json instead of settings.json) and a different trigger (claude plugin install instead of permission grant). Cross-file evidence + suggested struct-level fix posted in #59870.

github-actions[bot] · 3 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.