{"record":{"id":"0eb0dd4fd97d1345","repo":"Hmbown/CodeWhale","slug":"staged-plugin-manifest-failed-validation-error","errorCode":null,"errorMessage":"staged plugin manifest failed validation: {error}","messagePattern":"staged plugin manifest failed validation: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/plugins/install/stage.rs","lineNumber":76,"sourceCode":"\n#[cfg(not(unix))]\nfn ensure_plugins_dir(user_plugins_dir: &Path) -> Result<()> {\n    fs::create_dir_all(user_plugins_dir).with_context(|| {\n        format!(\n            \"failed to create user plugins directory {}\",\n            user_plugins_dir.display()\n        )\n    })\n}\n\n/// Validate the staged tree and return the manifest name + content hash.\npub(super) fn validate_staged(staged_path: &Path) -> Result<(String, String)> {\n    let manifest_path = crate::plugins::agent_plugin::resolve_manifest_path(staged_path)\n        .ok_or_else(|| {\n            anyhow::anyhow!(\"staged bundle has no plugin.json, .claude-plugin/plugin.json, kimi.plugin.json, or plugin.toml\")\n        })?;\n    let validated = PluginManifest::validate_from_path(&manifest_path)\n        .map_err(|error| anyhow::anyhow!(\"staged plugin manifest failed validation: {error}\"))?;\n    let name = validated.manifest.plugin.name.clone();\n    validate_skill_name_segment(&name).map_err(|error| {\n        anyhow::anyhow!(\"[plugin].name is not a safe directory name: {error:#}\")\n    })?;\n    Ok((name, validated.content_hash))\n}\n\n/// Copy a local bundle directory into staging. Symlinks anywhere in the\n/// source are rejected; a stale `.installed-from` marker is never copied so\n/// provenance always reflects *this* install.\npub(super) fn stage_local_copy(\n    source: &Path,\n    user_plugins_dir: &Path,\n    max_size: u64,\n) -> Result<StagedPlugin> {\n    // Validate the source first; this also rejects symlinked roots/manifests.\n    let manifest_path =\n        crate::plugins::agent_plugin::resolve_manifest_path(source).ok_or_else(|| {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/plugins/install/stage.rs#L58-L94","documentation":"The staged bundle's manifest was found, but `PluginManifest::validate_from_path` rejected it (bad JSON/TOML, missing required fields like [plugin].name or version, wrong types). The original validator error is embedded in the message so the specific failing field is visible.","triggerScenarios":"`validate_staged` (called from `stage_local_copy` and `stage_tarball`) calls `PluginManifest::validate_from_path(&manifest_path)` and the validator returns an error during plugin install staging.","commonSituations":"Hand-written manifest missing required keys, JSON/TOML syntax errors, wrong field types (e.g. version as a number), manifests produced by a newer/older schema version.","solutions":["Read the embedded `{error}` detail and fix that exact manifest field.","Validate plugin.json parses as JSON/TOML with a linter (e.g. `jq . plugin.json`).","Add required fields ([plugin].name, version, description) matching the current schema.","Copy the manifest shape from a known-working plugin and adjust values."],"exampleFix":"// before: plugin.json\n{ \"name\": \"my-plugin\" }\n// after\n{ \"plugin\": { \"name\": \"my-plugin\", \"version\": \"1.0.0\", \"description\": \"...\" } }","handlingStrategy":"validation","validationCode":"const manifest = JSON.parse(fs.readFileSync('plugin.json', 'utf8'));\nconst required = ['plugin.name', 'plugin.version'];\nfor (const key of required) {\n  if (!key.split('.').reduce((o, k) => o?.[k], manifest)) {\n    throw new Error(`plugin.json missing required field: ${key}`);\n  }\n}","typeGuard":"function isValidManifest(m) {\n  return m && typeof m === 'object' && m.plugin &&\n    typeof m.plugin.name === 'string' && m.plugin.name.length > 0 &&\n    typeof m.plugin.version === 'string';\n}","tryCatchPattern":"try {\n  await codewhale.plugins.install(src);\n} catch (e) {\n  if (e.message.startsWith('staged plugin manifest failed validation')) {\n    console.error('fix plugin.json per the embedded detail:', e.message);\n  } else throw e;\n}","preventionTips":["Lint plugin.json with `jq .` or a JSON schema validator before install.","Keep manifests in version control and validate them in CI.","Follow the current schema; copy the shape from a working plugin."],"tags":["plugins","manifest","schema-validation","rust"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}