{"record":{"id":"c25c51e21dc5ed08","repo":"astrid-runtime/astrid","slug":"signed-distro-lock-entry-does-not-match-distr","errorCode":null,"errorMessage":"signed Distro.lock entry '{}' does not match Distro.toml","messagePattern":"signed Distro\\.lock entry '(.+?)' does not match Distro\\.toml","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/init_signed_source.rs","lineNumber":361,"sourceCode":"        .map(|capsule| (capsule.name.as_str(), capsule))\n        .collect();\n    anyhow::ensure!(\n        declared.len() == manifest.capsules.len() && lock.capsules.len() == declared.len(),\n        \"signed Distro.lock members do not match Distro.toml declarations\"\n    );\n    for capsule in &lock.capsules {\n        let declared_capsule = declared\n            .get(capsule.name.as_str())\n            .copied()\n            .ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"signed Distro.lock contains undeclared capsule '{}'\",\n                    capsule.name\n                )\n            })?;\n        if capsule.source != declared_capsule.source || capsule.version != declared_capsule.version\n        {\n            bail!(\n                \"signed Distro.lock entry '{}' does not match Distro.toml\",\n                capsule.name\n            );\n        }\n        anyhow::ensure!(\n            !capsule.hash.is_empty(),\n            \"signed Distro.lock entry '{}' has no capsule hash\",\n            capsule.name\n        );\n    }\n    Ok(())\n}\n","sourceCodeStart":343,"sourceCodeEnd":374,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/init_signed_source.rs#L343-L374","documentation":"After verifying identity, validate_signed_member_sets checks each capsule entry in the Distro.lock against the capsule declared in the signed Distro.toml. If the lock's source URL or version for a capsule differs from the signed manifest, it bails naming the capsule — the lock would otherwise silently redirect an install to a different artifact than the signed one. A missing/empty hash is separately rejected by the ensure! right after.","triggerScenarios":"verify_signed_manifest -> validate_signed_member_sets: for a capsule in the lock, capsule.source != declared_capsule.source or capsule.version != declared_capsule.version. Happens when the lock pins an older/newer capsule version or a different source URL than what the current signed Distro.toml declares.","commonSituations":"Upstream bumped a capsule's version or moved its source in Distro.toml without the user re-locking; user hand-edited a capsule entry in Distro.lock; lock generated from a different signed manifest revision; dependency overridden to a mirror URL not in the signed manifest.","solutions":["Regenerate Distro.lock from the current signed Distro.toml so capsule source/version entries match the signed values.","If you need the older capsule version, fetch the signed Distro.toml revision that declares that version instead.","Stop hand-editing Distro.lock capsule entries; restore the file from version control and re-lock.","Ask the distro maintainer to re-sign an updated Distro.toml if the change is intentional on your side (e.g. you need a mirror URL)."],"exampleFix":"// before (Distro.lock capsule entry)\n[[capsules]]\nname = \"foo\"\nversion = \"1.0.0\"\nsource = \"https://old.example.com/foo-1.0.0.capsule\"\n// after (matches signed Distro.toml)\n[[capsules]]\nname = \"foo\"\nversion = \"1.1.0\"\nsource = \"https://example.com/distros/mydistro/v1.3/foo-1.1.0.capsule\"","handlingStrategy":"validation","validationCode":"for capsule in &lock.capsules {\n    if let Some(declared) = manifest.capsules.iter().find(|c| c.name == capsule.name) {\n        if capsule.source != declared.source || capsule.version != declared.version {\n            eprintln!(\"capsule {} drifted: lock={}:{} signed={}:{}\",\n                capsule.name, capsule.version, capsule.source, declared.version, declared.source);\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"match verify_signed_manifest(&client, &url, &manifest_hash, &lock, accept_new_key).await {\n    Err(e) if e.to_string().contains(\"does not match Distro.toml\") => {\n        let capsule = e.to_string().split('\\'').nth(1).unwrap_or(\"?\");\n        eprintln!(\"Capsule '{capsule}' differs between lock and signed manifest; run the lock workflow to re-pin it\");\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Regenerate Distro.lock after any upstream capsule version or source change","Treat Distro.lock as generated output — never edit capsule entries by hand","Resolve lock-vs-manifest conflicts by re-locking, not by overriding entries","Review signed-manifest diffs for capsule version bumps before upgrading"],"tags":["integrity","lockfile","capsule","version-mismatch","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"}