{"record":{"id":"e5fe16e06272dc99","repo":"astrid-runtime/astrid","slug":"signed-distro-toml-does-not-match-distro-lock-mani","errorCode":null,"errorMessage":"signed Distro.toml does not match Distro.lock manifest_hash; refusing to resolve members","messagePattern":"signed Distro\\.toml does not match Distro\\.lock manifest_hash; refusing to resolve members","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/init_signed_source.rs","lineNumber":296,"sourceCode":"    let mut response = response;\n    while let Some(chunk) = response.chunk().await? {\n        bytes.extend_from_slice(&chunk);\n        anyhow::ensure!(bytes.len() <= limit, \"{name} exceeds size limit\");\n    }\n    Ok(bytes)\n}\n\n/// Bind exact TOML bytes into the signed lock, then verify that lock.\nfn verify_signed_manifest(\n    home: &AstridHome,\n    manifest: &DistroManifest,\n    manifest_hash: &str,\n    lock: &DistroLock,\n    sig_hex: &str,\n    accept_new_key: bool,\n) -> anyhow::Result<HashMap<String, String>> {\n    if lock.manifest_hash.as_deref() != Some(manifest_hash) {\n        bail!(\n            \"signed Distro.toml does not match Distro.lock manifest_hash; refusing to resolve members\"\n        );\n    }\n    validate_signed_member_sets(manifest, lock)?;\n    let signing = manifest.distro.signing.as_ref().ok_or_else(|| {\n        anyhow::anyhow!(\"signed Distro.toml has no [distro.signing] configuration\")\n    })?;\n    let outcome = trust::verify_and_pin(\n        home,\n        &manifest.distro.id,\n        &signing.pubkey,\n        sig_hex,\n        lock,\n        accept_new_key,\n        trust::TrustPolicy::RequireExistingPin,\n    )?;\n    tracing::info!(\n        distro = %manifest.distro.id,","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/init_signed_source.rs#L278-L314","documentation":"verify_signed_manifest compares the manifest_hash recorded in the local Distro.lock against the hash of the signed Distro.toml that was just fetched and authenticated. If they differ, it refuses to resolve members because the signed manifest being used is not the one the lock file was generated from — proceeding could install capsules that were never covered by the lock's signature. This is an integrity check protecting the supply chain during signed-source init.","triggerScenarios":"fetch_signed_manifest calls verify_signed_manifest with the hash of the fetched signed Distro.toml and the local Distro.lock; lock.manifest_hash is None or differs from that hash — i.e. the signed Distro.toml was updated upstream after Distro.lock was created, or the lock file was edited/regenerated against a different manifest.","commonSituations":"Upstream distro published a new signed Distro.toml (new release) while the user's checkout still has an old Distro.lock; user hand-edited Distro.lock; lock generated from a different distro version than the signed manifest URL points to; hash computed over a locally modified manifest.","solutions":["Regenerate/update Distro.lock from the current signed Distro.toml (re-run the init/lock workflow for the new distro version) so manifest_hash matches.","Pin the fetched manifest: point the init command at the signed Distro.toml URL/tag that corresponds to the existing Distro.lock.","Verify you didn't hand-edit Distro.lock; restore it from version control or regenerate it.","Confirm the upstream distro actually intends the change (review the new signed manifest) before accepting the new state — don't bypass the check."],"exampleFix":"// before: stale lock\n// Distro.lock: manifest_hash = \"sha256:aaaa...\" but signed Distro.toml hashes to \"sha256:bbbb...\"\n// after: regenerate the lock against the new signed manifest\n$ astrid init --signed-source https://example.com/distros/mydistro/Distro.toml --regenerate-lock","handlingStrategy":"validation","validationCode":"if let Some(lock_hash) = &lock.manifest_hash {\n    let current = sha256_hex(signed_manifest_bytes);\n    if current != *lock_hash {\n        eprintln!(\"signed Distro.toml drifted from Distro.lock; re-lock before init\");\n    }\n}","typeGuard":null,"tryCatchPattern":"match fetch_signed_manifest(&client, &url, &lock).await {\n    Err(e) if e.to_string().contains(\"manifest_hash\") => {\n        eprintln!(\"Lock is stale relative to the signed Distro.toml; regenerate Distro.lock or pin the old manifest URL\");\n        regenerate_lock_and_retry().await?\n    }\n    Ok(m) => m,\n    Err(e) => return Err(e),\n}","preventionTips":["Commit Distro.lock and re-lock whenever the upstream signed Distro.toml changes","Pin the manifest URL to a release tag rather than a moving 'latest' path","Never hand-edit manifest_hash in Distro.lock","Diff the fetched signed Distro.toml against the last locked revision when upgrading"],"tags":["integrity","hash-mismatch","signature","lockfile","rust"],"backgroundTag":"checksum-mismatch","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"}