{"record":{"id":"5ddfc73d30c8bce0","repo":"astrid-runtime/astrid","slug":"runtime-tree-receipt-is-not-a-regular-file","errorCode":null,"errorMessage":"runtime tree receipt is not a regular file: {}","messagePattern":"runtime tree receipt is not a regular file: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/runtime_tree_admit.rs","lineNumber":181,"sourceCode":") -> io::Result<bool> {\n    let receipt_bytes = fs::metadata(receipt_path)?.len();\n    let catalog = store\n        .content()\n        .list(&StateOwner::System)\n        .map_err(|error| io::Error::other(format!(\"list packed runtime catalog: {error}\")))?;\n    Ok(catalog.iter().any(|entry| {\n        entry.name().as_str() == RECEIPT_RELATIVE_PATH && entry.logical_bytes() == receipt_bytes\n    }))\n}\n\nfn read_receipt(path: &Path) -> io::Result<Option<RuntimeTreeReceipt>> {\n    let metadata = match fs::symlink_metadata(path) {\n        Ok(metadata) => metadata,\n        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(None),\n        Err(error) => return Err(error),\n    };\n    if !metadata.is_file() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\n                \"runtime tree receipt is not a regular file: {}\",\n                path.display()\n            ),\n        ));\n    }\n    if metadata.len() > MAX_RECEIPT_BYTES {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"runtime tree receipt exceeds {MAX_RECEIPT_BYTES} bytes\"),\n        ));\n    }\n    astrid_core::platform_fs::validate_private_file(path)?;\n    let bytes = fs::read(path)?;\n    serde_json::from_slice(&bytes).map(Some).map_err(|error| {\n        io::Error::new(\n            io::ErrorKind::InvalidData,","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/runtime_tree_admit.rs#L163-L199","documentation":"The runtime tree receipt path exists but `symlink_metadata` shows it is not a regular file — e.g. a directory or a symlink. The kernel only accepts regular files as receipts, because receipts are read atomically and validated as private files. This is raised as InvalidData with the offending path in the message.","triggerScenarios":"`read_receipt` (called by `admit_blocking`) finds metadata where `!metadata.is_file()`: the receipt path is a directory, a symlink (to anywhere), a fifo, or another special file.","commonSituations":"A user or tool replaced the receipt with a symlink (e.g. linking it to shared state); a directory was created at the receipt path by mistake; restore tools recreated the path as a symlink.","solutions":["Remove the directory/symlink at the receipt path and let the app regenerate a real receipt file","Re-run admission — an absent receipt is handled gracefully, so deleting the bogus path is safe","Check with `ls -la` whether the path is a symlink and where it points","Restore the receipt from backup as a plain regular file, not a link"],"exampleFix":"# before\n$ ls -la receipt.json\nreceipt.json -> /shared/receipt.json\n# after\n$ rm receipt.json\n# restart app; it recreates the receipt as a regular file","handlingStrategy":"validation","validationCode":"let md = std::fs::symlink_metadata(&receipt_path)?;\nif !md.is_file() {\n    std::fs::remove_file(&receipt_path)?; // allow regeneration\n}","typeGuard":"fn is_regular_file(p: &Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)\n}","tryCatchPattern":"if let Some(e) = err.downcast_ref::<io::Error>() {\n    if e.kind() == io::ErrorKind::InvalidData && msg.contains(\"not a regular file\") {\n        std::fs::remove_file(&path)?; // then retry admission\n    }\n}","preventionTips":["Never symlink receipts to shared/external locations","Restore receipts as plain files, not links or directories","Check `ls -la` on the home after manual restores"],"tags":["filesystem","receipt","invalid-state"],"backgroundTag":"path-is-not-a-directory","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"}