{"record":{"id":"9ff12a6e4d9d9043","repo":"astrid-runtime/astrid","slug":"legacy-capsule-metadata-version-differs-for-id","errorCode":null,"errorMessage":"legacy capsule metadata version differs for {id}","messagePattern":"legacy capsule metadata version differs for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage/migration.rs","lineNumber":144,"sourceCode":"        }\n        let id = target\n            .file_name()\n            .and_then(|name| name.to_str())\n            .ok_or_else(|| anyhow::anyhow!(\"legacy capsule entry has a non-UTF-8 name\"))?;\n        let manifest = astrid_capsule::discovery::load_manifest(&target.join(\"Capsule.toml\"))\n            .with_context(|| format!(\"read legacy capsule manifest {id}\"))?;\n        if manifest.package.name != id {\n            bail!(\n                \"legacy capsule directory {id} does not match manifest id {}\",\n                manifest.package.name\n            );\n        }\n        let meta_bytes = fs::read(target.join(\"meta.json\"))\n            .with_context(|| format!(\"read legacy capsule metadata {id}\"))?;\n        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\"))?;","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage/migration.rs#L126-L162","documentation":"The legacy capsule's meta.json records an installed version that must agree with the version in Capsule.toml. If serde-decoded meta.version differs from manifest.package.version, the install is internally inconsistent and migration aborts for that capsule.","triggerScenarios":"meta.json was written for an older/newer install than the current Capsule.toml; the manifest was upgraded without reinstalling; a partial update overwrote one of the two files.","commonSituations":"Manually replacing Capsule.toml with a newer version during development; interrupted upgrade leaving stale meta.json; restored backup mixing file generations.","solutions":["Reinstall the capsule so meta.json and Capsule.toml are regenerated consistently","Update meta.json's version to match the manifest only if you are certain the install matches","Delete the inconsistent install and migrate a clean copy","Restore both files from the same backup generation"],"exampleFix":"// before (meta.json)\n{\"version\": \"1.0.0\"}  // Capsule.toml says 1.2.0\n// after\nreinstall capsule so meta.json records 1.2.0","handlingStrategy":"validation","validationCode":"fn versions_agree(capsule_dir: &Path) -> Result<(), String> {\n    let manifest = astrid_capsule::discovery::load_manifest(&capsule_dir.join(\"Capsule.toml\")).map_err(|e| e.to_string())?;\n    let meta: CapsuleMeta = serde_json::from_slice(&std::fs::read(capsule_dir.join(\"meta.json\")).map_err(|e| e.to_string())?)\n        .map_err(|e| e.to_string())?;\n    if meta.version != manifest.package.version { return Err(\"meta/manifest version mismatch\".into()); }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = migrate_native_capsules(home, store) {\n    if e.to_string().contains(\"metadata version differs\") {\n        eprintln!(\"reinstall the capsule so meta.json matches Capsule.toml, then retry\");\n    } else { return Err(e); }\n}","preventionTips":["Upgrade capsules through the installer, never by hand-editing Capsule.toml","Restore meta.json and Capsule.toml from the same backup generation","Check both files after any interrupted upgrade","Keep capsule processes from writing version metadata during migration"],"tags":["migration","version-mismatch","metadata","capsule"],"backgroundTag":"version-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"}