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

Đang mở
#94,451 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
area:plugins bug has repro platform:linux platform:wsl
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á.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.