claude-code - 💡(How to fix) Fix [BUG] Cowork plugin upload fails with generic "Plugin validation failed" when a `description` field in any SKILL.md frontmatter contains angle brackets (`<…>`)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

After bisecting over ~10 builds by stripping frontmatter fields one at a time, the trigger turned out to be the literal characters < and > appearing inside the description: field of any skills/<skill>/SKILL.md frontmatter. The validator appears to be HTML/XML-sanitizing that field and treating <x> as a tag — but the rejection is silent (no specific error pointing at the offending file or character), so it took many iterations to find.

  1. Surface a specific, actionable error message. Instead of "Plugin validation failed", the upload UI should say something like "description in skills/deputy/SKILL.md contains disallowed characters: '<', '>'", pointing at the file and field. The generic error makes this prohibitively expensive to diagnose — there's no way for an admin to tell whether the rejection is about file size, file extension, ZIP structure, manifest schema, an individual SKILL.md, or any specific character.

Error Messages/Logs

No further detail in the upload modal, no expandable error, no console output, no network response body visible to the admin user. Nothing in the org's audit log either, as far as we could tell.

Fix Action

Fix / Workaround

   ---
   name: example
   description: Pass `<name> <prompt>` as arguments to dispatch an example.
   ---

Code Example

UI shows only:


Plugin validation failed


No further detail in the upload modal, no expandable error, no console output, no network response body visible to the admin user. Nothing in the org's audit log either, as far as we could tell.

---

my-plugin/
   ├── .claude-plugin/
   │   └── plugin.json
   └── skills/
       └── example/
           └── SKILL.md

---

{
     "name": "my-plugin",
     "version": "0.1.0",
     "description": "Repro for Cowork upload validation"
   }

---

---
   name: example
   description: Pass `<name> <prompt>` as arguments to dispatch an example.
   ---

   # Example skill

   Body text.
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

When uploading a plugin to Cowork via Organization settings → Plugins, the upload is rejected with a generic "Plugin validation failed" and no further detail in the UI.

After bisecting over ~10 builds by stripping frontmatter fields one at a time, the trigger turned out to be the literal characters < and > appearing inside the description: field of any skills/<skill>/SKILL.md frontmatter. The validator appears to be HTML/XML-sanitizing that field and treating <x> as a tag — but the rejection is silent (no specific error pointing at the offending file or character), so it took many iterations to find.

For us, the offending text was a perfectly natural placeholder convention in a CLI-style description: Pass \<name> <prompt>` as arguments`. The exact same SKILL.md is accepted by Claude Code CLI without issue — only the Cowork upload validator rejects it.

What Should Happen?

Two things, in order of importance:

  1. Surface a specific, actionable error message. Instead of "Plugin validation failed", the upload UI should say something like "description in skills/deputy/SKILL.md contains disallowed characters: '<', '>'", pointing at the file and field. The generic error makes this prohibitively expensive to diagnose — there's no way for an admin to tell whether the rejection is about file size, file extension, ZIP structure, manifest schema, an individual SKILL.md, or any specific character.

  2. Ideally, allow <…> in description. It's valid in a YAML scalar and natural for documenting CLI argument placeholders (<name>, <prompt>, <path>, etc.). If the validator must strip/escape to be HTML-safe in the marketplace UI, it should escape on render, not reject on input.

Error Messages/Logs

UI shows only:


Plugin validation failed


No further detail in the upload modal, no expandable error, no console output, no network response body visible to the admin user. Nothing in the org's audit log either, as far as we could tell.

Steps to Reproduce

  1. Create a minimal plugin directory with this structure:

    my-plugin/
    ├── .claude-plugin/
    │   └── plugin.json
    └── skills/
        └── example/
            └── SKILL.md
  2. .claude-plugin/plugin.json:

    {
      "name": "my-plugin",
      "version": "0.1.0",
      "description": "Repro for Cowork upload validation"
    }
  3. skills/example/SKILL.mdnote the angle brackets in the description:

    ---
    name: example
    description: Pass `<name> <prompt>` as arguments to dispatch an example.
    ---
    
    # Example skill
    
    Body text.
  4. Zip the plugin: cd my-plugin && zip -r ../my-plugin.zip .

  5. Upload my-plugin.zip via Cowork Organization settings → Plugins → Upload.

Result: Upload rejected with "Plugin validation failed".

  1. Now edit skills/example/SKILL.md and replace <name> <prompt> with [name] [prompt] (or any non-<> form). Rebuild the zip and re-upload.

Result: Upload succeeds with no other changes.

Claude Model

None

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.1.153

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Bisection ruled out the following as causes (all of these pass validation):

  • Square brackets in description ([name] [prompt])
  • Backticks in description (`name prompt`)
  • Em-dash and other non-ASCII characters in description
  • Long descriptions (~500 chars)
  • The argument-hint: frontmatter field
  • The allowed-tools: frontmatter field
  • The contents of bash scripts under the skill's directory
  • The presence of .pytest_cache/ directories inside the zip
  • File extension .plugin vs .zip
  • Nested vs flat zip layout (plugin/ prefix vs no prefix)

Only < / > in the description field triggers the rejection.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING