{"record":{"id":"32541379233f14ba","repo":"astrid-runtime/astrid","slug":"durable-capsule-id-is-missing-wit-file-relative","errorCode":null,"errorMessage":"durable capsule {id} is missing WIT file {relative}","messagePattern":"durable capsule (.+?) is missing WIT file (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":225,"sourceCode":"    let mut expected = std::collections::BTreeSet::new();\n    for (relative, pin) in &metadata.wit_files {\n        let relative_path = Path::new(relative);\n        if relative_path.is_absolute()\n            || relative_path.components().any(|component| {\n                matches!(\n                    component,\n                    std::path::Component::ParentDir | std::path::Component::RootDir\n                )\n            })\n            || relative_path\n                .components()\n                .any(|component| !matches!(component, std::path::Component::Normal(_)))\n        {\n            bail!(\"durable capsule {id} has unsafe WIT metadata path {relative}\");\n        }\n        let key = format!(\"wit/{relative}\");\n        let Some(bytes) = files.get(&key) else {\n            bail!(\"durable capsule {id} is missing WIT file {relative}\");\n        };\n        if !is_hex_digest(pin) || blake3::hash(bytes).to_hex().as_str() != pin {\n            bail!(\"durable capsule {id} WIT digest mismatch for {relative}\");\n        }\n        expected.insert(key);\n    }\n    for key in files.keys().filter(|key| key.starts_with(\"wit/\")) {\n        if Path::new(key)\n            .extension()\n            .is_some_and(|extension| extension.eq_ignore_ascii_case(\"wit\"))\n            && !expected.contains(key)\n        {\n            bail!(\"durable capsule {id} has an unpinned WIT file {key}\");\n        }\n    }\n    Ok(())\n}\n","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L207-L243","documentation":"verify_wit_files looks up each WIT file listed in the capsule metadata under the `wit/` key in the archive's in-memory file map. If the archive does not contain the file the metadata pins, the package is internally inconsistent — metadata and archive disagree — and reading the durable package fails rather than silently missing an interface definition.","triggerScenarios":"read_verified_durable_package_for_owner on a capsule where metadata.wit_files declares a relative path whose corresponding `wit/<relative>` entry is absent from the archive files — e.g. the WIT file was deleted or renamed after metadata was generated, or the archive was rebuilt without it.","commonSituations":"Renaming/removing a .wit file without republishing; partial archive upload/truncation dropping files; editing the durable store to update one side only; version drift between metadata and archive.","solutions":["Re-add the missing .wit file to the capsule source and republish/reinstall the capsule.","Regenerate metadata so wit_files matches the actual archive contents (rebuild the capsule package).","If the archive was truncated in transit, re-download/reinstall from the registry.","Verify consistency locally before publishing by digesting the built archive."],"exampleFix":"// before: metadata pins types.wit but archive lacks it\n// metadata.wit_files = {\"types.wit\": pin}; archive has only wit/api.wit\n// after: restore or republish so both sides agree\ncp types.wit wit/ && republish capsule","handlingStrategy":"validation","validationCode":"fn all_pinned_wits_present(metadata_wit_files: &[(String, String)], archive_files: &[String]) -> bool {\n    metadata_wit_files.iter().all(|(rel, _)| archive_files.iter().any(|f| f == &format!(\"wit/{rel}\")))\n}","typeGuard":"fn wit_file_in_archive(rel: &str, files: &std::collections::BTreeMap<String, Vec<u8>>) -> bool {\n    files.contains_key(&format!(\"wit/{rel}\"))\n}","tryCatchPattern":"match read_verified_durable_package_for_owner(id) {\n    Err(e) if e.to_string().contains(\"is missing WIT file\") => {\n        // metadata/archive disagreement: republish or reinstall the capsule\n        reinstall_capsule(id)?;\n    }\n    other => other?,\n}","preventionTips":["Regenerate metadata whenever WIT files are added, renamed, or removed","Never edit archive contents or metadata independently","Verify archives fully downloaded/transferred before installing","Digest the built archive locally before publishing to catch missing files"],"tags":["metadata","integrity","wit","package"],"backgroundTag":"record-not-found","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}