astrid-runtime/astrid · critical
signed shuttle for '{distro_id}' is missing its manifest_has
Error message
signed shuttle for '{distro_id}' is missing its manifest_hash binding — refusing. The signature covers the lock, not Distro.toml; without manifest_hash the manifest (env/selection) is unauthenticated and could be swapped. What it means
For a signed shuttle, check_manifest_binding requires lock.manifest_hash to be present. The signature covers the lock, not Distro.toml itself, so without the recorded manifest_hash the manifest (environment and capsule selection) is unauthenticated and could be silently swapped. Signed artifacts missing this binding are hard-refused rather than installed.
Source
Thrown at crates/astrid-cli/src/commands/distro/shuttle_install.rs:285
/// Pure (no I/O) so the binding gate is unit-testable.
fn check_manifest_binding(
distro_id: &str,
signed: bool,
lock: &DistroLock,
manifest_bytes: &[u8],
) -> anyhow::Result<()> {
let actual = manifest_hash(manifest_bytes);
match &lock.manifest_hash {
Some(recorded) => {
if recorded != &actual {
bail!(
"manifest hash mismatch: lock records {recorded}, archive Distro.toml hashes \
to {actual} — the shuttle is inconsistent or tampered"
);
}
Ok(())
},
None if signed => bail!(
"signed shuttle for '{distro_id}' is missing its manifest_hash binding — refusing. \
The signature covers the lock, not Distro.toml; without manifest_hash the manifest \
(env/selection) is unauthenticated and could be swapped."
),
None => Ok(()),
}
}
/// Verify the per-capsule blake3 of every lock entry against the bytes
/// actually present in the mirror. Returns an error on the first
/// mismatch or missing file. Pure (no install side effects) so the
/// integrity gate is unit-testable.
fn verify_capsule_hashes(mirror: &Path, lock: &DistroLock) -> anyhow::Result<()> {
for entry in &lock.capsules {
let file = shuttle::capsule_mirror_path(mirror, &entry.name);
if !file.is_file() {
bail!(
"capsule '{}' is missing from the shuttle mirror",View on GitHub (pinned to affd8760f4)
Solutions
- Rebuild the shuttle with the current packing tool so the signed lock includes manifest_hash
- Regenerate signatures with an up-to-date sealing workflow rather than hand-editing the lock
- If the shuttle must remain unsigned, distribute it unsigned — do not sign a lock without the hash binding
Example fix
// before: signed lock without manifest_hash // after: repack with the current astrid version // astrid distro pack --sign <key> --output /media/shuttle
Defensive patterns
Strategy: validation
Validate before calling
if lock.signature.is_some() && lock.manifest_hash.is_none() {
return Err(anyhow!("signed lock missing manifest_hash binding"));
} Prevention
- Use the current packing tool for signed shuttles
- Reject hand-edited lock files in review
- Test signed shuttles with a manifest-binding check before distribution
When it happens
Trigger: install_from_shuttle with a signed lock that lacks a manifest_hash field — typically produced by an older packing tool version, a hand-crafted lock, or a lock stripped during editing.
Common situations: Old shuttles packed before manifest_hash binding was introduced; manually edited or stripped lock files; mixing a new signed lock format with an old tool or vice versa.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- capsule provenance changed after authority decision
- durable capsule {id} provenance differs from authority recei
- durable capsule {id} authority claims provenance absent from
- distro '{distro_id}' is pinned to {} but this artifact is si
- manifest exceeds its installed capability approval: {details
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/6c320ea175d954a5.
Report an issue: GitHub.