{"record":{"id":"f2fa4f261ac318aa","repo":"astrid-runtime/astrid","slug":"leftover-capsule-authority-receipt-is-not-a-regula","errorCode":null,"errorMessage":"leftover capsule authority receipt is not a regular file: {}","messagePattern":"leftover capsule authority receipt is not a regular file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/authority/leftover.rs","lineNumber":71,"sourceCode":"        );\n    }\n    if !status.previous.is_empty() {\n        bail!(\n            \"cannot retire leftover capsule authority while previous transaction artifact exists at {}\",\n            status.previous[0].display()\n        );\n    }\n    Ok(status.unknown_active)\n}\n\n/// Parse a regular-file leftover receipt. Invalid JSON returns `Ok(None)`.\npub(crate) fn parse_legacy_authority_receipt(\n    path: &Path,\n) -> anyhow::Result<Option<(InstalledAuthority, Vec<u8>)>> {\n    let metadata = fs::symlink_metadata(path)\n        .with_context(|| format!(\"inspect leftover capsule authority {}\", path.display()))?;\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 bytes = fs::read(path)\n        .with_context(|| format!(\"read leftover capsule authority {}\", path.display()))?;\n    let Ok(receipt) = serde_json::from_slice::<InstalledAuthority>(&bytes) else {\n        return Ok(None);\n    };\n    if receipt.schema_version != 1 {\n        return Ok(None);\n    }","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/authority/leftover.rs#L53-L89","documentation":"`parse_legacy_authority_receipt` only accepts regular files as leftover authority receipts. This error is thrown when `symlink_metadata` shows the path is a symlink, directory, or other non-regular file. Receipts are security-sensitive: a symlink could redirect reads elsewhere, so the library hard-fails instead of following it (invalid JSON, by contrast, is tolerated as `Ok(None)`).","triggerScenarios":"Calling `parse_legacy_authority_receipt` (used by `unique_relocated_receipt`, `leftover_id_counts`, `retire_one_leftover`) on a path inside the legacy authority directory that is a symlink or not a regular file — e.g. someone symlinked a receipt to another location, or a directory was created where a receipt file should be.","commonSituations":"User convenience symlinks placed into the authority receipt directory to share receipts across homes; backup/restore tools that replaced files with symlinks; a directory accidentally created where a `.json` receipt belongs.","solutions":["Replace the symlink or non-regular entry with a real regular-file receipt (copy the target's bytes into the authority directory), then retry","If the entry is not a valid receipt, remove it or quarantine it manually and rerun the leftover sweep","Audit the home's authority receipt directory for symlinks and ensure restore/copy tooling dereferences symlinks into plain files"],"exampleFix":"// before: authority dir contains a symlinked receipt\nbail!(\"leftover capsule authority receipt is not a regular file: {}\", path.display());\n// after: replace symlink with a regular file\n// let target = fs::read_link(&path)?;\n// fs::remove_file(&path)?;\n// fs::copy(target, &path)?;   // then retry the sweep","handlingStrategy":"validation","validationCode":"// Inspect leftover receipt paths before parsing\nlet metadata = fs::symlink_metadata(&path)?;\nif metadata.file_type().is_symlink() || !metadata.is_file() {\n    // replace with a regular file or quarantine the entry before the sweep\n}","typeGuard":"fn is_regular_file(path: &Path) -> bool {\n    std::fs::symlink_metadata(path)\n        .map(|m| !m.file_type().is_symlink() && m.is_file())\n        .unwrap_or(false)\n}","tryCatchPattern":"match parse_legacy_authority_receipt(&path) {\n    Err(e) if e.to_string().contains(\"not a regular file\") => quarantine_or_replace(&path)?,\n    other => other,\n}","preventionTips":["Never symlink receipts into or out of the authority directory","Configure backup/restore tooling to materialize copies, not symlinks","Audit the authority receipt directory for symlinks and odd entries after restores","Use quarantine or retirement flows instead of hand-placing files in receipt directories"],"tags":["security","filesystem","symlink","authority-receipt"],"backgroundTag":"incompatible-source-type","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"}