astrid-runtime/astrid · error
Distro.lock capsule '{capsule}' has an invalid BLAKE3 hash
Error message
Distro.lock capsule '{capsule}' has an invalid BLAKE3 hash What it means
The lock's WASM hash string must parse as a BLAKE3 hash after the `blake3:` prefix. `blake3::Hash::from_hex` failed, so the value after the prefix is not valid hexadecimal of the right length. The library refuses to validate the capsule because it cannot even parse the pinned hash, distinguishing this from the separate canonical-form (lowercase, 64 chars) check.
Source
Thrown at crates/astrid-cli/src/commands/init_grant.rs:429
"Distro.lock capsule '{}' content blob is missing or unreadable at {}",
capsule,
blob_path.display()
)
})?
};
let actual = blake3::hash(&bytes);
if actual != locked {
bail!("Distro.lock capsule '{capsule}' content blob bytes do not match hash {locked_hash}");
}
Ok(())
}
fn parse_locked_blake3(capsule: &CapsuleId, value: &str) -> anyhow::Result<blake3::Hash> {
let Some(hex) = value.strip_prefix("blake3:") else {
bail!("Distro.lock capsule '{capsule}' requires a canonical blake3:<hex> WASM hash");
};
let hash = blake3::Hash::from_hex(hex).map_err(|_| {
anyhow::anyhow!("Distro.lock capsule '{capsule}' has an invalid BLAKE3 hash")
})?;
if hex.len() != 64 || hash.to_hex().as_str() != hex {
bail!("Distro.lock capsule '{capsule}' requires a canonical lowercase BLAKE3 hash");
}
Ok(hash)
}
fn manifest_declares_wasm(manifest: &CapsuleManifest) -> bool {
manifest
.components
.iter()
.any(|component| component.path.extension().and_then(|ext| ext.to_str()) == Some("wasm"))
}
/// Apply capsule-access grants for the installed set (opt-in), or print
/// the discoverability hint when the flag was omitted.
///
/// On the grant path the capsules are already installed and the lock isView on GitHub (pinned to affd8760f4)
Solutions
- Regenerate Distro.lock so it contains the correct `blake3:<64-hex>` hash from the built WASM
- Compute the correct hash with `b3sum <capsule>.wasm` and paste it (keeping the `blake3:` prefix)
- Restore the lock from the signed source (`Distro.lock` fetch) instead of editing locally
- Ensure any tooling writing the lock emits lowercase 64-character hex
Example fix
# before wasm = "blake3:abc123" # after wasm = "blake3:2f1e..." # full 64-char lowercase hex from b3sum
Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_blake3_lock(value: &str) -> bool {
value.strip_prefix("blake3:")
.map(|h| h.len() == 64 && h.bytes().all(|b| b.is_ascii_hexdigit()))
.unwrap_or(false)
} Type guard
fn canonical_blake3(value: &str) -> Option<blake3::Hash> {
let hex = value.strip_prefix("blake3:")?;
let hash = blake3::Hash::from_hex(hex).ok()?;
(hex.len() == 64 && hash.to_hex().as_str() == hex).then_some(hash)
} Try / catch
match res {
Err(e) if e.to_string().contains("invalid BLAKE3 hash") => regenerate_lock(),
other => other,
} Prevention
- Never hand-edit hash fields in Distro.lock; use b3sum
- Always keep the `blake3:` prefix and 64-char lowercase hex
- Validate the lock after any scripted generation
- Restore locks from the signed source rather than patching
When it happens
Trigger: `parse_locked_blake3` receives a value like `blake3:xyz...` where the hex part contains invalid characters or wrong length, making `from_hex` return Err. Any hand-edited or programmatically generated lock with a malformed hash triggers this.
Common situations: Hand-editing Distro.lock and mistyping the hash; using an MD5/SHA-256 hex string instead of BLAKE3; truncating the hash when copying; generating the lock with a script that writes a placeholder value.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- capsule archive already contains {PROVENANCE_FILE}
- Distro.lock exceeds 1 MB limit
- durable capsule {} has malformed contracts pin
- refusing to seed canonical from a non-content-address contra
- --retain-entries must be at least 1
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/69c4963860edcb5d.
Report an issue: GitHub.