astrid-runtime/astrid · error · io::Error
principal-store capability entry is redirected or not a…
Error message
principal-store capability entry is redirected or not a regular file
What it means
validate_regular checks that an opened principal-store capability file is a real regular file and not a symlink or redirected entry; on failure it raises this InvalidData error. Like the directory check, it guarantees the store never reads or writes through redirected file entries. The wrapper text "inspect principal-store capability file" propagates the underlying metadata error if stat fails.
Solutions
- Remove the symlink or non-regular entry and restore a real regular file at that path
- Copy the target data back into a genuine file inside the store instead of linking to it
- Restrict write access to the store root to prevent symlink planting
- Re-run store integrity checks after fixing the entry
Example fix
// before ln -s /shared/blob store/principals/tenant-a/data.bin // after rm store/principals/tenant-a/data.bin && cp /shared/blob store/principals/tenant-a/data.bin
Defensive patterns
Strategy: validation
Validate before calling
fn assert_regular_file(p: &Path) -> io::Result<()> {
let md = p.symlink_metadata()?;
if !md.is_file() || md.file_type().is_symlink() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "not a regular file"));
}
Ok(())
} Type guard
fn is_plain_file(p: &Path) -> bool {
std::fs::symlink_metadata(p).map(|m| m.is_file() && !m.file_type().is_symlink()).unwrap_or(false)
} Try / catch
match open_rw_result {
Err(e) if e.kind() == io::ErrorKind::InvalidData => {
// restore a real regular file at the path, then retry
}
r => r,
} Prevention
- Never replace store files with symlinks, FIFOs, or device nodes
- Restrict write access to capability directories
- Validate entries with symlink_metadata before opening the store
- Investigate immediately — this check failing often signals tampering or tooling bugs
When it happens
Trigger: Calling open_rw or create_private on a path where the entry is a symlink, device node, FIFO, or directory instead of a regular file; or where file_is_redirected detects redirection metadata on the opened handle.
Common situations: A developer symlinked a data file to shared storage; a tooling bug replaced a file with a FIFO/socket; tampering attempts inside a world-writable store directory.
Related errors
- legacy principal home root is not a regular directory
- legacy principal profile is not a regular file
- legacy state source contains a redirect
- legacy state source is redirected
- principal-store capability entry is redirected or not a…
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/5e8092803b914dae.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-storage/src/engine/durable/native_io.rs:178
use cap_std::fs::OpenOptionsExt as _;
options.custom_flags(libc::O_NOFOLLOW | libc::O_NONBLOCK);
}
#[cfg(windows)]
{
use cap_std::fs::OpenOptionsExt as _;
use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_OPEN_REPARSE_POINT;
options.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT);
}
}
fn validate_regular(file: &NativeFile) -> Result<(), DurableError> {
let metadata = file
.metadata()
.map_err(|source| io_error("inspect principal-store capability file", source))?;
if !metadata.is_file() || file_is_redirected(&metadata) {
return Err(io_error(
"validate principal-store capability file",
io::Error::new(
io::ErrorKind::InvalidData,
"principal-store capability entry is redirected or not a regular file",
),
));
}
Ok(())
}
#[cfg(windows)]
fn file_is_redirected(metadata: &std::fs::Metadata) -> bool {
use std::os::windows::fs::MetadataExt as _;
use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT;
metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0
}
#[cfg(not(windows))]
const fn file_is_redirected(_metadata: &std::fs::Metadata) -> bool {View on GitHub (pinned to affd8760f4)