{"record":{"id":"58c6673763010760","repo":"astrid-runtime/astrid","slug":"leftover-capsule-authority-receipt-changed-before","errorCode":null,"errorMessage":"leftover capsule authority receipt changed before retirement: {}","messagePattern":"leftover capsule authority receipt changed before retirement: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/authority/leftover.rs","lineNumber":170,"sourceCode":"            path.display()\n        )\n    })?;\n    if metadata.file_type().is_symlink() || !metadata.is_file() {\n        bail!(\n            \"leftover capsule authority receipt is not a regular file: {}\",\n            path.display()\n        );\n    }\n    astrid_core::platform_fs::verify_no_redirects(path).with_context(|| {\n        format!(\n            \"verify leftover capsule authority receipt {}\",\n            path.display()\n        )\n    })?;\n    let actual = fs::read(path)\n        .with_context(|| format!(\"read leftover capsule authority {}\", path.display()))?;\n    if actual != expected_bytes {\n        bail!(\n            \"leftover capsule authority receipt changed before retirement: {}\",\n            path.display()\n        );\n    }\n    fs::remove_file(path).with_context(|| {\n        format!(\n            \"retire leftover capsule authority receipt {}\",\n            path.display()\n        )\n    })?;\n    if let Some(parent) = path.parent() {\n        sync_authority_directory(parent)?;\n    }\n    Ok(())\n}\n\nfn unique_relocated_receipt(\n    home: &AstridHome,","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/authority/leftover.rs#L152-L188","documentation":"retire_unmatched_authority_receipt_file re-reads the leftover receipt immediately before fs::remove_file and compares it to the expected bytes captured earlier. If they differ, the file was mutated between ingestion/quarantine and retirement, so deleting it would destroy data the library cannot vouch for — hence the error.","triggerScenarios":"Calling retire_one_leftover → retire_unmatched_authority_receipt_file when the file content at leftover.rs:167-174 changed after the expected bytes were captured: a concurrent writer (another tool instance, sync daemon, editor) modified the receipt during the ingest-then-retire window.","commonSituations":"Two astrid processes running concurrently on the same home; a text editor or sync tool auto-saving the receipt; antivirus quarantining/rewriting the file mid-operation.","solutions":["Close other processes and re-run the operation so the read-then-delete window is uncontended","Re-run from scratch: the tool re-reads the (now stable) receipt and retires it against fresh expected bytes","If the change was intentional, re-run ingestion so the new bytes become the expected bytes before retirement","Check filesystem/journal health if corruption rather than concurrent writes is suspected"],"exampleFix":"// before\n$ astrid migrate &  # plus a second instance editing the receipt\nerror: leftover capsule authority receipt changed before retirement\n// after\n$ pkill -f astrid\n$ astrid migrate  # single process, stable file -> succeeds","handlingStrategy":"validation","validationCode":"let before = std::fs::read(path)?;\n// pass `before` as expected_bytes and ensure no other process writes between read and retire\nassert!(retire_unmatched_authority_receipt_file(path, &before).is_ok());","typeGuard":"fn receipt_unchanged(p: &Path, expected: &[u8]) -> bool {\n    std::fs::read(p).map(|a| a == expected).unwrap_or(false)\n}","tryCatchPattern":"if let Err(e) = retire_unmatched_authority_receipt_file(path, &expected) {\n    if e.to_string().contains(\"changed before retirement\") {\n        // re-read fresh bytes and re-ingest before retiring\n        let fresh = std::fs::read(path)?;\n        // re-ingest(fresh) then retire against fresh\n    } else { return Err(e); }\n}","preventionTips":["Serialize all astrid operations on a home directory (file lock or single process)","Exclude the authority directory from editors/daemons that auto-save","Verify receipt stability (two reads equal) before invoking retirement"],"tags":["filesystem","integrity-check","concurrency","data-loss-prevention"],"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"}