{"record":{"id":"ffc5fdb97c6938db","repo":"jdx/mise","slug":"vfox-plugin-archive-must-contain-metadata-lua-at-i","errorCode":null,"errorMessage":"vfox plugin archive must contain metadata.lua at its root","messagePattern":"vfox plugin archive must contain metadata\\.lua at its root","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/plugins/packslip.rs","lineNumber":240,"sourceCode":"                continue;\n            }\n            let Component::Normal(name) = component else {\n                bail!(\"vfox plugin archive contains an unsafe path\");\n            };\n            let name = name.to_string_lossy();\n            ensure!(\n                !name.contains(['\\\\', ':'])\n                    && !name.eq_ignore_ascii_case(\".git\")\n                    && !name.eq_ignore_ascii_case(STATE_FILE),\n                \"vfox plugin archive contains a reserved or unsafe path\"\n            );\n        }\n    }\n    Ok(())\n}\n\npub(crate) fn validate_layout(path: &Path) -> Result<()> {\n    ensure!(\n        path.join(\"metadata.lua\").is_file(),\n        \"vfox plugin archive must contain metadata.lua at its root\"\n    );\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn plugin_artifact_contract() {\n        let payload = packslip::sigstore::peek_statement(include_str!(\n            \"../../test/fixtures/packslip-vfox/packslip.sigstore.json\"\n        ))\n        .unwrap();\n        let mut statement: packslip::model::Statement = serde_json::from_slice(&payload).unwrap();\n        let artifact = statement.predicate.artifacts.remove(0);","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/plugins/packslip.rs#L222-L258","documentation":"After a vfox plugin archive is extracted, mise validates its layout: `metadata.lua` must exist as a regular file at the extraction root. The metadata file declares the plugin's name, versions, and install logic, so a plugin without it cannot function. This error means the archive extracted but is not a valid vfox plugin layout.","triggerScenarios":"Installing/parsing a vfox plugin packslip archive where metadata.lua is missing, is in a subdirectory (e.g. plugin-name/metadata.lua), or exists only as a symlink/directory rather than a file.","commonSituations":"Plugin author archives the repo root including a wrapping top-level directory from `tar -czf out.tar.gz my-plugin/`, or the metadata file was renamed/deleted, or only source.lua files were packaged.","solutions":["Repackage so metadata.lua sits at the archive root: `tar -czf plugin.tar.gz -C my-plugin .`.","Confirm metadata.lua actually exists in the plugin repository and is named exactly `metadata.lua`.","Ensure metadata.lua is a regular file, not a symlink or directory."],"exampleFix":"// before: tar -czf plugin.tar.gz my-plugin/    -> my-plugin/metadata.lua\n// after\ntar -czf plugin.tar.gz -C my-plugin .        -> metadata.lua","handlingStrategy":"validation","validationCode":"# shell: verify the archive layout before publishing/installing\ntar -tzf plugin.tar.gz | grep -qx 'metadata.lua' && echo OK || echo 'REJECTED: metadata.lua not at archive root'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Archive the plugin directory contents (`tar -C plugin-dir .`) so metadata.lua lands at the root.","Keep metadata.lua checked in at the repo/plugin root and never rename it.","Test the packaged archive with `mise plugin install` in CI before publishing."],"tags":["archive","validation","missing-file","vfox"],"backgroundTag":"file-not-found","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}