{"record":{"id":"c2d167708ed31c82","repo":"astrid-runtime/astrid","slug":"component-migration-ledger-is-missing-path","errorCode":null,"errorMessage":"component migration ledger is missing: {path}","messagePattern":"component migration ledger is missing: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/secret.rs","lineNumber":26,"sourceCode":"use astrid_core::principal::PrincipalId;\n\nuse super::host_fs::read_bounded_file;\nuse super::ledger::{MigrationLedger, decode_canonical};\nuse super::{MAX_BYTES, ledger_path, reject_incomplete_layout_v2};\n\n#[cfg(test)]\nuse super::ledger::{DestinationProof, MigrationComponent, SourceIdentity, canonical_json};\n\n/// Return whether migration provenance forbids a legacy secret source for a\n/// principal that participated in migration.\npub(crate) fn legacy_secret_source_must_be_absent(\n    home: &AstridHome,\n    uid: PrincipalUid,\n) -> io::Result<bool> {\n    reject_incomplete_layout_v2(home)?;\n    let path = ledger_path(home);\n    let bytes = read_bounded_file(&path, MAX_BYTES)?.ok_or_else(|| {\n        io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"component migration ledger is missing: {}\", path.display()),\n        )\n    })?;\n    let ledger: MigrationLedger = decode_canonical(&bytes, &path)?;\n    let name = format!(\"principal:{uid}:secrets\");\n    let component = ledger\n        .components\n        .iter()\n        .find(|component| component.name == name);\n    Ok(component.is_some_and(|component| !component.source.present))\n}\n\npub(crate) fn ensure_legacy_secret_deletion_allowed(\n    home: &AstridHome,\n    principal: &PrincipalId,\n    uid: PrincipalUid,\n) -> io::Result<()> {","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/secret.rs#L8-L44","documentation":"The component migration ledger file (returned by `ledger_path`) could not be read because it does not exist. `legacy_secret_source_must_be_absent` requires the ledger to decide whether a principal's legacy secret source must be absent; without it, provenance cannot be established, so it fails with InvalidData before any deletion check can proceed.","triggerScenarios":"Calling `ensure_legacy_secret_deletion_allowed` (or `legacy_secret_source_must_be_absent` directly) for a home where `reject_incomplete_layout_v2` passes but the migration ledger file was never created — i.e. the migration that writes the ledger never ran on this home.","commonSituations":"Pointing the kernel at a fresh or partially initialized AstridHome; deleting or losing the ledger file while keeping the migrated layout; running deletion logic before running the layout migration.","solutions":["Run the layout migration / initialization flow first so the component migration ledger is written at the expected path.","Check that `AstridHome` points at the correct home directory (wrong HOME/ASTRID_HOME env var is a common cause).","If the ledger was accidentally deleted, restore it from backup or re-run the import to regenerate it.","Verify the ledger path from `ledger_path(home)` exists and is readable before calling principal-deletion APIs."],"exampleFix":"// before: deleting a principal on a home never migrated\nkernel.ensure_legacy_secret_deletion_allowed(&home, &principal, uid)?;\n// after: complete migration first\nmigrate_layout_to_v2(&home)?; // writes the component migration ledger\nkernel.ensure_legacy_secret_deletion_allowed(&home, &principal, uid)?;","handlingStrategy":"validation","validationCode":"let ledger = ledger_path(&home);\nif !ledger.exists() {\n    return Err(format!(\"run layout migration first; missing ledger at {}\", ledger.display()));\n}\nensure_legacy_secret_deletion_allowed(&home, &principal, uid)?;","typeGuard":"fn ledger_present(home: &AstridHome) -> bool { ledger_path(home).is_file() }","tryCatchPattern":"match ensure_legacy_secret_deletion_allowed(&home, &principal, uid) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains(\"ledger is missing\") => {\n        eprintln!(\"home not migrated; run the migration flow first\");\n    }\n    other => other?,\n}","preventionTips":["Always run the layout migration before any principal-deletion flow.","Check that HOME/ASTRID_HOME points at the intended home.","Back up the migration ledger; treat it as required state."],"tags":["migration","ledger","file-not-found","io"],"backgroundTag":"config-file-not-found","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}