anthropics / anthropics/claude-code
[BUG] known_marketplaces.json is never repaired once invalid: one entry missing lastUpdated (or a parse error) disables plugins from every marketplace, and the reconciler, marketplace add and marketplace remove all fail re-reading it
- Ngôn ngữ chính
- Python
- Star
- 145k
- Fork
- 23.1k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
### Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
### What's Wrong?
When `known_marketplaces.json` fails to load, Claude Code has everything it needs to rebuild it: every marketplace is still declared in `extraKnownMarketplaces`. It even tries. The reconciler logs `failed to load known_marketplaces.json, treating as empty` and reinstalls each declared marketplace. **Every one of those installs fails, because the install's write re-reads and re-validates the same invalid file and aborts.** The file is never repaired, on that launch or any later one, and no plugin from **any** marketplace loads.
Two triggers, same outcome:
1. **One entry missing `lastUpdated`.** The schema check rejects the whole file (`Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input`), so one bad entry disables the plugins of every *other*, fully valid marketplace. The log shows it directly: installing the valid `mkt-b` fails with `mkt-a`'s error.
2. **A JSON parse error** (a truncated file). Same reconciler sequence, same result.
The CLI cannot get out of it either. `claude plugin marketplace remove` and `claude plugin marketplace add` fail with the same error, and `claude plugin list` reports both plugins as `✔ enabled` while every launch loads zero of them. The only recovery is deleting the file by hand. A *missing* file is the one failed state Claude Code does heal: it rebuilds it and the launch after that loads everything.
In my case the entry without `lastUpdated` came from a local repair script, not from Claude Code, which always writes the field. But this file goes invalid through plenty of routes, Claude Code's own included: a UTF-8 BOM from Windows tooling (#84501), a zero-byte file from an interrupted write (#19065), a trailing comma written by `/plugin marketplace add` (#56967). Whatever the route, one bad entry should not cost every plugin, and the repair Claude Code already attempts should be able to land.
### What Should Happen?
1. **Validate per entry.** Skip (or quarantine) an entry that fails the schema and keep loading the rest, rather than rejecting the file.
2. **Let the reconciler's rebuild land.** When the file cannot be loaded at all, move it aside (e.g. `known_marketplaces.json.corrupt-`) and rebuild it from `extraKnownMarketplaces`, instead of routing every install through a write path that re-reads the invalid file and aborts. The reconciler has already decided to treat the file as empty; the writer is the only part that disagrees.
3. **Let `claude plugin marketplace remove` work on an invalid file.** It is the natural manual fix, and today it fails with the same error.
A startup warning (#84501's second ask) would help, but on its own it still leaves every plugin disabled until the user finds and deletes an internal file.
### Error Messages/Logs
```shell
# debug log, second launch; mkt-a's entry lacks lastUpdated, mkt-b's is valid, both declared in extraKnownMarketplaces
[DEBUG] Registered 0 hooks from 0 plugins
[ERROR] reconciler: failed to load known_marketplaces.json, treating as empty: Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
[DEBUG] [reconcile] 2 marketplace(s): mkt-a(install), mkt-b(install)
[ERROR] [reconcile] failed to install marketplace 'mkt-a': Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
[ERROR] [reconcile] failed to install marketplace 'mkt-b': Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
# the same launch also logs
[ERROR] Plugin autoupdate: failed: Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
[ERROR] syncDeclaredAutoUpdateToJson: failed to update known_marketplaces.json: Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
# truncated file instead: identical sequence with
[ERROR] reconciler: failed to load known_marketplaces.json, treating as empty: Failed to load marketplace configuration: JSON Parse error: Unterminated string
[ERROR] [reconcile] failed to install marketplace 'mkt-b': Failed to load marketplace configuration: JSON Parse error: Unterminated string
```
### Steps to Reproduce
Runs against an isolated config dir. No login is needed, because plugin loading and the reconciler run before the auth check (each `-p` launch exits with `Not logged in`, which does not affect the result).
```bash
# Isolated config dir; no login needed (plugin loading and the reconciler run before the auth check).
R=$(mktemp -d); mkdir -p "$R/cfg/plugins" "$R/home"
for m in a b; do
d="$R/mkt-$m"; p="$d/plugins/plugin-$m"
mkdir -p "$d/.claude-plugin" "$p/.claude-plugin" "$p/hooks"
echo "{\"name\":\"mkt-$m\",\"owner\":{\"name\":\"demo\"},\"plugins\":[{\"name\":\"plugin-$m\",\"source\":\"./plugins/plugin-$m\"}]}" > "$d/.claude-plugin/marketplace.json"
echo "{\"name\":\"plugin-$m\",\"version\":\"0.0.1\"}" > "$p/.claude-plugin/plugin.json"
echo '{"hooks":{"SessionStart":[{"hooks":[{"type":"command","command":"true"}]}]}}' > "$p/hooks/hooks.json"
done
cat > "$R/cfg/settings.json" < "$KM" </dev/null 2>&1; done
grep -hE 'Registered|\[reconcile\]|reconciler:' "$R/launch2.log" | cut -c26-
cc plugin marketplace remove mkt-a
cc plugin marketplace add "$R/mkt-a"
cc plugin list
echo "== 2. truncated file"
printf '%s' '{"mkt-a": {"source": {"sou' > "$KM"
for i in 3 4; do cc -p noop --debug-file "$R/launch$i.log" >/dev/null 2>&1; done
grep -hE 'Registered|\[reconcile\]|reconciler:' "$R/launch4.log" | cut -c26-
cc plugin marketplace remove mkt-a
echo "== 3. control: delete the file"
rm "$KM"
for i in 5 6; do cc -p noop --debug-file "$R/launch$i.log" >/dev/null 2>&1; done
grep -h 'Registered' "$R/launch5.log" "$R/launch6.log" | cut -c26-
```
Observed on 2.1.272 (verbatim; ANSI colour codes stripped):
```
== 1. mkt-a's entry has no lastUpdated; mkt-b's entry is valid
[DEBUG] Registered 0 hooks from 0 plugins
[ERROR] reconciler: failed to load known_marketplaces.json, treating as empty: Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
[DEBUG] [reconcile] 2 marketplace(s): mkt-a(install), mkt-b(install)
[ERROR] [reconcile] failed to install marketplace 'mkt-a': Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
[ERROR] [reconcile] failed to install marketplace 'mkt-b': Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
✘ Failed to remove marketplace: Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
Adding marketplace…✘ Failed to add marketplace: Marketplace configuration file is corrupted: mkt-a.lastUpdated: Invalid input
Installed plugins:
❯ plugin-a@mkt-a
Version: 0.0.1
Scope: user
Status: ✔ enabled
❯ plugin-b@mkt-b
Version: 0.0.1
Scope: user
Status: ✔ enabled
== 2. truncated file
[DEBUG] Registered 0 hooks from 0 plugins
[ERROR] reconciler: failed to load known_marketplaces.json, treating as empty: Failed to load marketplace configuration: JSON Parse error: Unterminated string
[DEBUG] [reconcile] 2 marketplace(s): mkt-a(install), mkt-b(install)
[ERROR] [reconcile] failed to install marketplace 'mkt-a': Failed to load marketplace configuration: JSON Parse error: Unterminated string
[ERROR] [reconcile] failed to install marketplace 'mkt-b': Failed to load marketplace configuration: JSON Parse error: Unterminated string
✘ Failed to remove marketplace: Failed to load marketplace configuration: JSON Parse error: Unterminated string
== 3. control: delete the file
[DEBUG] Registered 0 hooks from 0 plugins
[DEBUG] Registered 2 hooks from 2 plugins
```
Cases 1 and 2 print the same thing on every further launch; the file is never rewritten. Case 3 is the control: with the file gone, the first launch rebuilds it and the second loads both plugins.
### Claude Model
Not applicable. The failure happens before any model call.
### Is this a regression?
I don't know. In earlier runs of mine, a truncated file with a single declared marketplace was also left unrepaired on 2.1.121, 2.1.140 and 2.1.150. I can't tell when `lastUpdated` became required.
### Last Working Version
_No response_
### Claude Code Version
2.1.272 (Claude Code)
### Platform
Other. Reproduces without authentication.
### Operating System
Ubuntu/Debian Linux (WSL2)
### Terminal/Shell
bash, non-interactive (`claude -p` and `claude plugin …` subcommands)
### Additional Information
Related, but not the same bug: #84501 (BOM trigger; asks to tolerate it on read and warn at startup), #19065 (empty-file hang), #56967 (Claude Code writing a trailing comma). Those are ways into this state. This report is about why Claude Code's own repair can't get back out of it, and why a single invalid entry takes down every marketplace. Two related CHANGELOG entries fixed other things: 2.1.246 (`claude plugin install` now reports an error on a corrupted file instead of exiting silently) and 2.1.232 (a concurrent-write race).
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Đánh giá
Issue này chưa được đánh giá.