{"record":{"id":"053c1ec01298ba01","repo":"BigPizzaV3/CodexPlusPlus","slug":"downloaded-openai-plugins-marketplace-is-invalid","errorCode":null,"errorMessage":"downloaded openai/plugins marketplace is invalid","messagePattern":"downloaded openai/plugins marketplace is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/plugin_marketplace.rs","lineNumber":478,"sourceCode":"    let mut components = path.components();\n    match components.next()? {\n        Component::Normal(_) => {}\n        _ => return None,\n    }\n    let mut relative = PathBuf::new();\n    for component in components {\n        match component {\n            Component::Normal(value) => relative.push(value),\n            Component::CurDir => {}\n            _ => return None,\n        }\n    }\n    (!relative.as_os_str().is_empty()).then_some(relative)\n}\n\nfn validate_openai_plugins_marketplace_root(root: &Path) -> anyhow::Result<()> {\n    let marketplace = local_openai_curated_marketplace_root_from_root(root)?\n        .ok_or_else(|| anyhow::anyhow!(\"downloaded openai/plugins marketplace is invalid\"))?;\n    if marketplace != root {\n        anyhow::bail!(\"downloaded openai/plugins marketplace root mismatch\");\n    }\n    Ok(())\n}\n\nfn validate_openai_curated_remote_marketplace_root(root: &Path) -> anyhow::Result<()> {\n    let marketplace = local_openai_curated_remote_marketplace_root_from_root(root)?\n        .ok_or_else(|| anyhow::anyhow!(\"embedded official remote plugin marketplace is invalid\"))?;\n    if marketplace != root {\n        anyhow::bail!(\"embedded official remote plugin marketplace root mismatch\");\n    }\n    Ok(())\n}\n\nfn local_openai_curated_marketplace_root_from_root(root: &Path) -> anyhow::Result<Option<PathBuf>> {\n    let marketplace_path = root\n        .join(\".agents\")","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/plugin_marketplace.rs#L460-L496","documentation":"validate_openai_plugins_marketplace_root (crates/codex-plus-core/src/plugin_marketplace.rs:476) checks a freshly extracted marketplace tree: local_openai_curated_marketplace_root_from_root must find .agents/plugins/marketplace.json, parse it as JSON, see name == OPENAI_CURATED_MARKETPLACE, a non-empty plugins array, and a plugins/ directory at the root. Any miss returns None and this 'downloaded openai/plugins marketplace is invalid' error aborts the install. Note the inner helper also propagates read/parse errors with their own context, so this message specifically means 'layout/manifest check failed'.","triggerScenarios":"Installing a downloaded marketplace zip whose root lacks .agents/plugins/marketplace.json, has a manifest with the wrong `name`, an empty `plugins` list, or a missing plugins/ directory — e.g. upstream restructured the archive, the zip has an extra top-level folder, or the download served a different artifact.","commonSituations":"Upstream changing the archive layout between releases (extra nesting level, renamed manifest); a URL redirect serving an HTML error page that unzips partially; internal mirrors repacking the zip with a different root; version skew between an old core crate and a new artifact format.","solutions":["Inspect the extracted tree (the staging dir under ~/.tmp/plugins) — check where marketplace.json actually landed; if it is one level deeper, the zip has an extra root folder (that shape instead trips error 38's root-mismatch path in some forks — here it means not found at all)","Verify the manifest: .agents/plugins/marketplace.json must be valid JSON with name matching OPENAI_CURATED_MARKETPLACE and a non-empty plugins array, plus a plugins/ sibling directory","Re-download from the official OPENAI_PLUGINS_ZIP_URL on a clean network path and retry — transient corruption and proxy HTML pages are common causes","If upstream genuinely changed layout, update local_openai_curated_marketplace_root_from_root / expectations in plugin_marketplace.rs to the new shape (with tests) and fall back to the embedded copy meanwhile"],"exampleFix":"# before: zip has an unexpected extra top-level folder\nmarketplace.zip\n└── openai-plugins-main/      # extra nesting\n    └── .agents/plugins/marketplace.json   # not at extract root\n\n# after: manifest directly at root\nmarketplace.zip\n└── .agents/plugins/marketplace.json\n└── plugins/","handlingStrategy":"validation","validationCode":"// Validate the extracted tree shape before calling install\nfn marketplace_tree_valid(root: &Path) -> bool {\n    let manifest = root.join(\".agents\").join(\"plugins\").join(\"marketplace.json\");\n    let Ok(text) = std::fs::read_to_string(&manifest) else { return false };\n    let Ok(v) = serde_json::from_str::<serde_json::Value>(&text) else { return false };\n    v.get(\"name\").and_then(|n| n.as_str()).is_some()\n        && v.get(\"plugins\").and_then(|p| p.as_array()).is_some_and(|a| !a.is_empty())\n        && root.join(\"plugins\").is_dir()\n}","typeGuard":"fn manifest_looks_like_marketplace(value: &serde_json::Value, expected_name: &str) -> bool {\n    value.get(\"name\").and_then(|n| n.as_str()) == Some(expected_name)\n        && value.get(\"plugins\").and_then(|p| p.as_array()).is_some_and(|a| !a.is_empty())\n}","tryCatchPattern":"match validate_openai_plugins_marketplace_root(&staging) {\n    Err(e) if e.to_string().contains(\"marketplace is invalid\") => {\n        tracing::warn!(\"downloaded marketplace failed layout check; keeping embedded copy\");\n        fallback_to_embedded_marketplace()?;\n    }\n    rest => rest?,\n}","preventionTips":["Verify .agents/plugins/marketplace.json exists at the archive root when producing artifacts","Pin the manifest `name` to the expected constant and keep a non-empty plugins array plus plugins/ dir","Run the marketplace validation unit tests in CI for any artifact-generation changes","Keep the embedded marketplace as fallback when downloaded validation fails"],"tags":["rust","plugin-marketplace","validation","manifest","layout"],"backgroundTag":"marketplace-manifest-missing","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}