astrid-runtime/astrid · error
materialized capsule digest does not match durable registry
Error message
materialized capsule digest does not match durable registry
What it means
This error means the digest recorded in the cache path (components[2]) does not match the blake3 hash of the package archive bytes in the loaded snapshot. The kernel throws it as an integrity check: the cached bytes on disk differ from what the cache key claims, so the materialized capsule may be corrupted, tampered with, or stale relative to the durable registry content.
Solutions
- Delete the mismatched cache entry (<cache-root>/<uid>/<name>/<wrong-digest>) and re-materialize the capsule from the registry
- Re-download/re-fetch the capsule to get a pristine archive, then retry
- Check disk health and exclude the cache directory from backup/AV mutation if files were modified externally
- If the cache is seeded by tooling, compute the blake3 digest of the final archive bytes and use that as the directory name
Example fix
// before: labeling cache with a digest from metadata let dir = cache_root.join(name).join(manifest_digest.clone()); // after: digest must hash the actual archive bytes let digest = blake3::hash(&archive_bytes).to_hex().to_string(); let dir = cache_root.join(name).join(digest);
Defensive patterns
Strategy: validation
Validate before calling
let digest = blake3::hash(&snapshot.package().archive).to_hex().to_string();
if digest != expected_digest { return Err("archive digest mismatch before materialization"); } Try / catch
match result {
Err(e) if e.to_string().contains("digest does not match") => {
// purge the bad cache entry and re-fetch from the registry
}
other => other?,
} Prevention
- Verify digests immediately after download, before caching
- Exclude cache dirs from AV/backup tools that modify files
- Check disk health if mismatches recur
- Always derive cache keys from the hash of the actual bytes
When it happens
Trigger: During cache validation after materialization: blake3::hash(snapshot.package().archive) differs from the digest component of the cache directory name — e.g. truncated or partially-written archive, an archive overwritten after the cache dir was created, bit-rot on disk, or a cache entry seeded with the wrong digest label.
Common situations: Interrupted download/materialization leaving a partial archive; antivirus or backup tooling modifying files in the cache; manually editing or replacing cache contents; disk corruption; reusing a cache volume copied inconsistently (digest dir name from one version, bytes from another).
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- durable capsule content digest differs from authority…
- durable capsule manifest digest differs from authority…
- installed Capsule.toml differs from the exact manifest…
- capsule cache owner or id does not match authenticated…
- capsule cache path does not contain owner/id/digest…
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/326ae1b116aaeac2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:1610
"capsule cache path contains unsafe components"
)),
})
.collect::<anyhow::Result<_>>()?;
if components.len() != 3 {
anyhow::bail!("capsule cache path does not contain owner/id/digest components");
}
let uid = self
.principal_directory
.uid_for(principal)
.map_err(|error| anyhow::anyhow!("resolve capsule cache owner UID: {error}"))?;
if components[0] != uid.to_string() || components[1] != manifest.package.name {
anyhow::bail!("capsule cache owner or id does not match authenticated registry scope");
}
let digest = blake3::hash(&snapshot.package().archive)
.to_hex()
.to_string();
if components[2] != digest {
anyhow::bail!("materialized capsule digest does not match durable registry");
}
Ok(())
}
/// Inventory a projection without traversing redirects or special files.
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
fn inventory_projection_files(root: &Path) -> anyhow::Result<ProjectionInventory> {
fn walk(
root: &Path,
directory: &Path,
inventory: &mut ProjectionInventory,
) -> anyhow::Result<()> {
for entry in std::fs::read_dir(directory).map_err(|error| {
anyhow::anyhow!("read capsule projection {}: {error}", directory.display())
})? {
let entry = entry
.map_err(|error| anyhow::anyhow!("read capsule projection entry: {error}"))?;
let path = entry.path();View on GitHub (pinned to affd8760f4)