{"record":{"id":"9948e1453c144d7b","repo":"astrid-runtime/astrid","slug":"legacy-capsule-authority-identity-differs-for-id","errorCode":null,"errorMessage":"legacy capsule authority identity differs for {id}","messagePattern":"legacy capsule authority identity differs for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage/migration.rs","lineNumber":159,"sourceCode":"        let meta: CapsuleMeta = serde_json::from_slice(&meta_bytes)\n            .with_context(|| format!(\"decode legacy capsule metadata {id}\"))?;\n        if meta.version != manifest.package.version {\n            bail!(\"legacy capsule metadata version differs for {id}\");\n        }\n        // Released pre-authority installs are admitted only through the\n        // existing one-time verifier. It pins their exact manifest,\n        // capabilities, and executable before any durable publication.\n        // Relocated homes keep receipts hashed from a previous absolute\n        // path; rebind a unique leftover onto this target first.\n        rebind_relocated_legacy_authority_receipt(home, &target, &manifest, workspace_targets)\n            .with_context(|| format!(\"rebind relocated leftover authority for {id}\"))?;\n        verify_installed_authority(home, &target, &manifest)\n            .with_context(|| format!(\"verify legacy capsule authority {id}\"))?;\n        let authority = read_installed_authority(home, &target)?.ok_or_else(|| {\n            anyhow::anyhow!(\"legacy capsule {id} authority verification produced no receipt\")\n        })?;\n        if authority.capsule_id != id || authority.version != manifest.package.version {\n            bail!(\"legacy capsule authority identity differs for {id}\");\n        }\n        let source_authority_bytes = read_installed_authority_bytes(home, &target)?\n            .ok_or_else(|| anyhow::anyhow!(\"legacy capsule {id} authority receipt disappeared\"))?;\n        let archive = canonical_legacy_archive(home, &target, &meta, &manifest)?;\n        let verification = artifact::verify_archive_bytes(&archive)\n            .with_context(|| format!(\"verify canonical legacy capsule archive {id}\"))?;\n        let mut durable_authority = authority;\n        verification\n            .content_digest()\n            .clone_into(&mut durable_authority.content_digest);\n        let durable_authority_bytes = serde_json::to_vec_pretty(&durable_authority)\n            .with_context(|| format!(\"serialize durable legacy capsule authority {id}\"))?;\n        let package = CapsulePackage::new(archive, meta_bytes, durable_authority_bytes);\n        let expectation = match registry.get_snapshot(&owner, id)? {\n            None => CapsuleInstallExpectation::Absent,\n            Some(snapshot) if snapshot.package() == &package => {\n                CapsuleInstallExpectation::Generation(snapshot.generation())\n            },","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage/migration.rs#L141-L177","documentation":"After verifying the installed authority receipt, migration checks that the receipt's capsule_id and version match the capsule being migrated. A mismatch means the pinned authority belongs to a different capsule or version, so migration refuses to publish it durably.","triggerScenarios":"The authority receipt on disk was written for a different id/version — e.g. a capsule was renamed or re-versioned in place, or receipts were copied between installs.","commonSituations":"Hand-copied receipt files between capsule directories; editing the manifest name/version without regenerating the authority receipt; restored backups mixing receipts.","solutions":["Regenerate/re-verify the authority receipt for this capsule so it carries the correct id and version","Restore the original manifest id/version that the receipt was issued for","Remove the stale receipt and reinstall the capsule through the normal verifier","Delete the mismatched install directory if it is a leftover"],"exampleFix":"// before\nreceipt: capsule_id=\"old-name\", version=\"1.0.0\"; dir/manifest: \"new-name\" 1.1.0\n// after\nre-run authority verification for \"new-name\" 1.1.0 so the receipt matches","handlingStrategy":"validation","validationCode":"fn receipt_matches(capsule_dir: &Path) -> Result<(), String> {\n    let receipt = read_installed_authority(home, capsule_dir)?\n        .ok_or(\"no authority receipt\")?;\n    let id = capsule_dir.file_name().unwrap().to_string_lossy().to_string();\n    let manifest = astrid_capsule::discovery::load_manifest(&capsule_dir.join(\"Capsule.toml\")).map_err(|e| e.to_string())?;\n    if receipt.capsule_id != id || receipt.version != manifest.package.version {\n        return Err(\"receipt identity mismatch\".into());\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = migrate_native_capsules(home, store) {\n    if e.to_string().contains(\"authority identity differs\") {\n        eprintln!(\"regenerate or restore the matching authority receipt, then retry\");\n    } else { return Err(e); }\n}","preventionTips":["Never copy authority receipts between capsule directories","Regenerate receipts whenever id or version changes","Let the normal verifier reinstall capsules instead of hand-assembling installs","Keep receipts and manifests from the same install generation"],"tags":["migration","authority","receipt","identity-mismatch","capsule"],"backgroundTag":"invalid-identifier","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"}