astrid-runtime/astrid · error
durable capsule component is missing from its archive
Error message
durable capsule {id} component is missing from its archive What it means
verify_package_identity looks up the first manifest component's relative path in the archive's file map (archive_files) to hash and verify it. This bail fires when no entry with that exact relative path exists in the archive, i.e. the manifest references a component file that is not actually packaged. The library throws it because the declared executable cannot be verified or executed if it is absent from the archive.
Solutions
- Repack the archive so it contains the file at exactly the path given by manifest.components[0].path.
- Fix the manifest's component path to match the actual archive entry name (paths are case- and prefix-sensitive).
- Reinstall the capsule from a complete, correctly packaged build instead of a partially assembled archive.
- List archive entries and diff them against manifest component paths to find the missing/renamed file.
Example fix
// before: manifest points at "bin/component.wasm" but archive only has "component.wasm" // after: align the path when packaging let relative = "component.wasm"; manifest.components[0].path = PathBuf::from(relative); archive_files.insert(relative.to_string(), wasm_bytes);
Defensive patterns
Strategy: validation
Validate before calling
for component in &manifest.components {
let key = component.path.to_str().ok_or_else(|| anyhow!("non-UTF-8 path"))?;
anyhow::ensure!(archive_files.contains_key(key), "archive missing component {key}");
} Prevention
- Repack the archive in the same build step that writes the manifest.
- Diff archive entry names against manifest component paths in CI packaging tests.
- Watch for case-sensitivity and path-prefix drift between manifest and packer.
When it happens
Trigger: Calling read_verified_durable_package_for_owner on a capsule where manifest.components[0].path (as a UTF-8 string) is not a key in the archive's BTreeMap of files — the manifest was edited/renamed without repacking, or the archive was built without including the component.
Common situations: Renaming the component file or its directory in the manifest but shipping the old archive; a packaging script that skips the wasm file (e.g. .gitignore or build output filtering); mismatched manifest and archive versions extracted from different builds; typos in the component path (case-sensitive lookup).
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- absent migration source has a digest
- alice
- an incomplete capsule authority update exists at
- audit fixture
- audit read failed
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/d88d83ae7935d3df.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-capsule-install/src/storage.rs:299
});
if metadata.imports != expected_imports {
bail!("durable capsule {id} imports differ between metadata and archive");
}
let expected_exports = crate::wit::version_map_to_strings(&manifest.exports, |definition| {
definition.version.to_string()
});
if metadata.exports != expected_exports {
bail!("durable capsule {id} exports differ between metadata and archive");
}
if authority.wasm_hash_pinned && metadata.wasm_hash != authority.approved_wasm_hash {
bail!("durable capsule {id} metadata executable hash differs from authority receipt");
}
if let Some(component) = manifest.components.first() {
let Some(relative) = component.path.to_str() else {
bail!("durable capsule {id} component path is not UTF-8");
};
let Some(bytes) = archive_files.get(relative) else {
bail!("durable capsule {id} component is missing from its archive");
};
if Path::new(relative)
.extension()
.is_some_and(|extension| extension.eq_ignore_ascii_case("wasm"))
{
let archive_hash = blake3::hash(bytes).to_hex().to_string();
if authority.wasm_hash_pinned
&& authority.approved_wasm_hash.as_deref() != Some(archive_hash.as_str())
{
bail!("durable capsule {id} WASM hash differs between authority and archive");
}
if metadata.wasm_hash.as_deref() != Some(archive_hash.as_str()) {
bail!("durable capsule {id} WASM hash differs between metadata and archive");
}
} else if metadata.wasm_hash.is_some() {
bail!("durable capsule {id} metadata names a hash for a non-WASM component");
}
} else if metadata.wasm_hash.is_some() {View on GitHub (pinned to affd8760f4)