[BUG] settings.json stale-write clobber silently disables installed plugins (continuation of #27941)
Preflight
- [x] Searched existing issues — closest match is #27941 (Config file silently reverts user changes — stale write detection logs telemetry but does not prevent overwrite). That issue was auto-closed by github-actions for inactivity and has now been auto-locked, so I'm filing this as the bot's "open a new issue" path requested.
- [x] Same root cause (
saveConfigWithLockstale-write detection logs telemetry without aborting; in-memory cache fallback). Different downstream symptom worth a fresh report: silent plugin disablement. - [x] Latest version of Claude Code (2.1.112).
Summary
The same stale-write mechanism documented in #27941 (and in the deeper duplicates #20637, #24578) clobbers enabledPlugins and extraKnownMarketplaces keys in settings.json, which silently disables previously-working plugins on every subsequent fresh CC session. installed_plugins.json is not load-sufficient — CC requires the boolean enablement flag in settings.json itself, so the moment a stale-snapshot session writes those keys back to null, the plugin is dead until manually re-enabled.
This is qualitatively worse than the MCP env-var case in #27941: at least there, claude mcp commands still saw the server. Here, the plugin's hooks/skills/commands are simply absent from new sessions, with no error message.
Reproduction (observed 2026-04-17 on CC 2.1.112)
- Install a local plugin:
claude plugin marketplace add /path/to/plugin && claude plugin enable myplugin@my-marketplace. Verifyinstalled_plugins.jsonand the two settings.json keys are populated. - Have a long-lived CC session running that started before step 1 (so its in-memory snapshot lacks the new keys). Trigger any routine mutation in that session —
/effort,/model, permission grant, etc. - The atomic rename overwrites
settings.jsonwith the stale snapshot → both keys go null. The plugin's directory andinstalled_plugins.jsonentry are untouched. - Start a fresh
claude -p "hi" --debug --debug-file=/tmp/debug.logsession. Debug log shows:
````
Loaded 20 installed plugins from .../installed_plugins.json
Found 6 plugins (6 enabled, 0 disabled)
Registered 1 hooks from 6 plugins
14 of 20 installed plugins are silently disabled — not a single warning surfaces in stdout, stderr, or the regular log. The plugin's SessionStart hooks never fire; its skills/commands are unavailable.
Why this is hard for users to detect
- No error message, no warning, no log line at WARN/ERROR level.
claude plugin listcontinues to show the plugin (it reads frominstalled_plugins.json).- Plugin functionality just stops appearing in new sessions. Users only notice when something they expected to work doesn't.
- Existing sessions keep working because plugin registration is loaded at session init (per documented hot-reload behavior); only fresh sessions are affected, so the symptom is intermittent and tied to "did I open a new terminal."
Proposed fix (cheaper of the #27941 options)
Re-read settings.json from disk before write in BOTH the file-lock path AND the cache fallback path. The original report's three-way merge is the correct fix but invasive — even a "re-read on stale detection, retry mutation against fresh content" loop would prevent the clobber here. Currently the stale detection just emits tengu_config_stale_write telemetry and proceeds with the stale write.
Workaround (in production today)
Shell wrapper around claude that runs the heal commands when keys are missing:
claude() {
local canonical="$HOME/.ccs/shared/settings.json"
if ! jq -e '.enabledPlugins["myplugin@my-marketplace"] == true and (.extraKnownMarketplaces["my-marketplace"].source.path // empty) != ""' "$canonical" >/dev/null 2>&1; then
command claude plugin marketplace add /path/to/plugin >/dev/null 2>&1
command claude plugin enable myplugin@my-marketplace >/dev/null 2>&1
fi
command claude "$@"
}
Effective but clearly not where this logic should live.
Environment
- CC 2.1.112
- Linux (WSL2 Ubuntu)
- Multi-session usage (CCS — Claude Code Switch — running ~20 concurrent CC sessions; the long-lived stale-snapshot pool is what makes the clobber happen so often)
References
- #27941 — original report, root cause analysis with code trace, auto-closed and auto-locked
- #20637 — multi-window race condition variant
- #24578 — Edit-tool wipe variant
- #27247 — confirms
enabledPluginsis load-gating (not cosmetic) —settings.local.jsonentry alone doesn't enable - #9537 — plugin marketplace removal doesn't clean settings.json (related plugin-keys lifecycle bug)
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗