{"record":{"id":"899e5c356a3c51b2","repo":"astrid-runtime/astrid","slug":"legacy-capsule-metadata-has-no-wasm-hash","errorCode":null,"errorMessage":"legacy capsule metadata has no WASM hash","messagePattern":"legacy capsule metadata has no WASM hash","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":655,"sourceCode":"    meta: &CapsuleMeta,\n    manifest: &astrid_capsule::manifest::CapsuleManifest,\n) -> anyhow::Result<Vec<u8>> {\n    let staging = tempfile::tempdir().context(\"stage legacy capsule for migration\")?;\n    copy_legacy_tree(target, staging.path())?;\n    if let Some(component) = manifest.components.first() {\n        let component_path = component.path.clone();\n        if component_path.is_absolute()\n            || component_path.components().any(|part| {\n                matches!(\n                    part,\n                    std::path::Component::ParentDir | std::path::Component::RootDir\n                )\n            })\n        {\n            bail!(\"legacy capsule component path is not relative\");\n        }\n        let Some(hash) = meta.wasm_hash.as_deref() else {\n            bail!(\"legacy capsule metadata has no WASM hash\");\n        };\n        let wasm = home.bin_dir().join(format!(\"{hash}.wasm\"));\n        let destination = staging.path().join(component_path);\n        if let Some(parent) = destination.parent() {\n            fs::create_dir_all(parent)?;\n        }\n        fs::copy(&wasm, &destination).with_context(|| {\n            format!(\"restore content-addressed WASM blob for {}\", wasm.display())\n        })?;\n    }\n    for (relative, hash) in &meta.wit_files {\n        let relative = Path::new(relative);\n        if relative.is_absolute()\n            || relative.components().any(|part| {\n                matches!(\n                    part,\n                    std::path::Component::ParentDir | std::path::Component::RootDir\n                )","sourceCodeStart":637,"sourceCodeEnd":673,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L637-L673","documentation":"During legacy migration, the component's WASM hash from the legacy metadata is used to locate the binary at home.bin_dir()/<hash>.wasm. If meta.wasm_hash is missing (None), the migration cannot locate or hash-verify the component and canonical_legacy_archive bails with this error.","triggerScenarios":"migrate_native_capsules_with_report encounters a legacy capsule whose meta file lacks the wasm_hash field — the field is absent, null, or an empty string filtered to None.","commonSituations":"Very old legacy capsules installed before wasm_hash was recorded; a hand-edited or truncated meta file; a partially-failed legacy install that wrote metadata without the hash.","solutions":["Compute the WASM hash (e.g. SHA-256 of the component .wasm) and add wasm_hash to the legacy meta file.","Reinstall the legacy capsule with a tool version that records wasm_hash, then rerun migration.","Delete the broken legacy capsule so migration can skip it or reinstall it cleanly."],"exampleFix":"// before (legacy meta.toml)\nname = \"foo\"\n# wasm_hash missing\n// after\nname = \"foo\"\nwasm_hash = \"<sha256 of foo.wasm>\"","handlingStrategy":"validation","validationCode":"match meta.wasm_hash.as_deref() {\n    Some(h) if !h.is_empty() => { /* ok */ }\n    _ => anyhow::bail!(\"legacy capsule {} has no wasm_hash; recompute before migrating\", meta.name),\n}","typeGuard":null,"tryCatchPattern":"match migrate_native_capsules_with_report(&home) {\n    Err(e) if e.to_string().contains(\"no WASM hash\") => {\n        warn!(\"legacy capsule missing wasm_hash; recomputing hashes\");\n        recompute_legacy_wasm_hashes(&home)?;\n        migrate_native_capsules_with_report(&home)?;\n    }\n    other => other,\n}","preventionTips":["Verify every legacy meta has a non-empty wasm_hash before starting migration.","Recompute hashes from the .wasm files when metadata is missing or suspect.","Keep legacy installs created by tooling that always records wasm_hash; skip and report capsules that predate it."],"tags":["migration","legacy","metadata","capsule"],"backgroundTag":"missing-required-config-field","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"}