astrid-runtime/astrid · error
runtime tree receipt is not a regular file
Error message
runtime tree receipt is not a regular file: {} What it means
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.
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
Example fix
# before $ ls -la receipt.json receipt.json -> /shared/receipt.json # after $ rm receipt.json # restart app; it recreates the receipt as a regular file
Defensive patterns
Strategy: validation
Validate before calling
let md = std::fs::symlink_metadata(&receipt_path)?;
if !md.is_file() {
std::fs::remove_file(&receipt_path)?; // allow regeneration
} Type guard
fn is_regular_file(p: &Path) -> bool {
std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)
} Try / catch
if let Some(e) = err.downcast_ref::<io::Error>() {
if e.kind() == io::ErrorKind::InvalidData && msg.contains("not a regular file") {
std::fs::remove_file(&path)?; // then retry admission
}
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- AlreadyExists
- AlreadyExists
- Astrid durable media is redirected or not a regular file
- Astrid home without a layout sentinel is redirected or not…
- Astrid volume is not a regular file
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/5ddfc73d30c8bce0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/runtime_tree_admit.rs:181
) -> io::Result<bool> {
let receipt_bytes = fs::metadata(receipt_path)?.len();
let catalog = store
.content()
.list(&StateOwner::System)
.map_err(|error| io::Error::other(format!("list packed runtime catalog: {error}")))?;
Ok(catalog.iter().any(|entry| {
entry.name().as_str() == RECEIPT_RELATIVE_PATH && entry.logical_bytes() == receipt_bytes
}))
}
fn read_receipt(path: &Path) -> io::Result<Option<RuntimeTreeReceipt>> {
let metadata = match fs::symlink_metadata(path) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(None),
Err(error) => return Err(error),
};
if !metadata.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"runtime tree receipt is not a regular file: {}",
path.display()
),
));
}
if metadata.len() > MAX_RECEIPT_BYTES {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("runtime tree receipt exceeds {MAX_RECEIPT_BYTES} bytes"),
));
}
astrid_core::platform_fs::validate_private_file(path)?;
let bytes = fs::read(path)?;
serde_json::from_slice(&bytes).map(Some).map_err(|error| {
io::Error::new(
io::ErrorKind::InvalidData,View on GitHub (pinned to affd8760f4)