[BUG] Plugin runtime loader and `claude plugin validate` accept divergent schemas
What's Wrong?
claude plugin validate and the runtime plugin loader use different schemas. The CLI accepts plugin manifests that the runtime rejects with Zod errors at install/load time. This makes the CLI validator unreliable as a pre-publish check.
I hit this twice in a row on the same plugin during initial publishing — each time, the CLI returned ✔ Validation passed and gh release create succeeded, but installing the published plugin in a clean Claude Code session failed with a Zod schema error from the runtime.
Both bugs match the same closed (auto-locked) issue: #31763.
What Should Happen?
claude plugin validate should use the same schema the runtime uses (or stricter). A manifest accepted by validate should always install successfully.
Error Messages/Logs
Case 1 — userConfig.<field>.enum (runtime, Claude Code 2.1.130+):
Failed to install: Plugin temp_local_1779351806694_0gsi8e has an invalid manifest file at
/Users/<user>/.claude/plugins/cache/.../.claude-plugin/plugin.json.
Validation errors: userConfig.default_framework: Unrecognized key: "enum",
userConfig.default_ui_framework: Unrecognized key: "enum",
userConfig.package_manager: Unrecognized key: "enum"
Case 2 — hooks/hooks.json without outer hooks wrapper (runtime, Claude Code 2.1.150):
Hook load failed: [
{
"expected": "record",
"code": "invalid_type",
"path": ["hooks"],
"message": "Invalid input: expected record, received undefined"
}
]
In both cases, claude plugin validate . returned ✔ Validation passed immediately before publishing.
Steps to Reproduce
Case 1 — userConfig.enum
- In a plugin directory, create
.claude-plugin/plugin.jsonwith auserConfigfield that uses anenumarray (a pattern that older plugin docs / JSON-Schema convention would suggest):
``json``
{
"name": "demo-plugin",
"version": "0.1.0",
"description": "Demo",
"userConfig": {
"framework": {
"type": "string",
"title": "Framework",
"description": "Pick one",
"enum": ["a", "b", "c"],
"default": "a"
}
}
}
- Add a minimal
.claude-plugin/marketplace.jsonand runclaude plugin validate .→ ✔ Validation passed.
- Publish, then try
/plugin install demo-plugin@your-marketplacein a clean Claude Code session.
- Runtime error:
Validation errors: userConfig.framework: Unrecognized key: "enum".
Case 2 — missing hooks wrapper in hooks/hooks.json
- In a plugin directory, create
hooks/hooks.jsonwith event arrays at the top level (matching the format that~/.claude/settings.jsonaccepts — which is what some older plugin docs suggested):
``json``
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": "echo hi", "timeout": 5 }
]
}
]
}
- Run
claude plugin validate .→ ✔ Validation passed.
- Install the plugin, then run
/doctor.
- Doctor reports:
Hook load failed: expected record at path "hooks", received undefined.
The runtime requires { "hooks": { "PostToolUse": [...] } }, but claude plugin validate accepts the unwrapped form.
Suggested Fix
Make claude plugin validate reuse the same Zod schemas the runtime loader uses (or have both consume the same source-of-truth). The Zod errors the runtime produces are already excellent — they'd be just as useful at CLI time, before publishing.
Until then, plugin authors have to do a fresh install on every release to confirm the runtime accepts what the validator did, and validate is effectively just a syntax check.
Related (closed, auto-locked, same error message): #31763.
Claude Model
Not relevant — this is a CLI / plugin-loader bug, not a model behavior issue.
Regression
Don't know — I'm a first-time plugin author. Both schemas may have been like this from the start.
Version
Hit on Claude Code 2.1.130 (Case 1, initial install attempts) and 2.1.150 (Case 2, doctor output). Both reproductions still happen on 2.1.150.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗