astrid-runtime/astrid · error · io::Error
representation namespace entry is redirected or has the…
Error message
representation namespace entry is redirected or has the wrong type
What it means
reject_redirect inspects symlink_metadata of a namespace entry and rejects it if it is a symlink/redirect or has the wrong type (directory expected when directory=true, regular file otherwise). This InvalidData error guards the contiguous-representation namespace against redirected or mistyped entries. It runs before each directory open in open_component.
Solutions
- Replace the symlink or mistyped entry with the correct object type (real directory or regular file)
- Do not create symlinks inside the representation namespace
- Fix the migration/tooling script that produced the wrong entry type
- Tighten store-directory permissions against third-party modification
Example fix
// before ln -s ../other-store/rep store/rep/abc // after rm store/rep/abc && mkdir store/rep/abc
Defensive patterns
Strategy: validation
Validate before calling
fn check_entry_type(p: &Path, want_dir: bool) -> io::Result<()> {
let md = std::fs::symlink_metadata(p)?;
let ok = if want_dir { md.is_dir() } else { md.is_file() };
if !ok || md.file_type().is_symlink() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "redirected or wrong type"));
}
Ok(())
} Type guard
fn is_correct_entry(p: &Path, want_dir: bool) -> bool {
std::fs::symlink_metadata(p)
.map(|m| !m.file_type().is_symlink() && (if want_dir { m.is_dir() } else { m.is_file() }))
.unwrap_or(false)
} Try / catch
match open_result {
Err(e) if e.kind() == io::ErrorKind::InvalidData => {
// fix entry type / remove symlink, then retry
}
r => r,
} Prevention
- Never symlink namespace entries
- Ensure migration scripts create the correct entry types (dirs vs files)
- Run pre-open layout validation on the representation tree
- Lock down store-directory write permissions
When it happens
Trigger: Calling open_component (and thereby reject_redirect) on an entry that is a symlink, or a file where a directory is expected (or vice versa); also triggered by filesystem redirection detected by is_redirect.
Common situations: Symlinking namespace entries to share representations between stores; a migration script created files where directories belong; tampering in a shared store directory.
Related errors
- inspect projected file
- layout migration destination is redirected or not a regular…
- layout migration source is redirected or not a directory
- legacy principal home root is not a regular directory
- legacy principal profile is not a regular file
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/6dee1e50feadf8e6.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-storage/src/engine/durable/representations/contiguous/namespace.rs:94
#[cfg(unix)]
{
directory.open(Path::new("."))?.into_std().sync_all()
}
#[cfg(not(unix))]
{
let _ = directory;
Ok(())
}
}
fn reject_redirect(parent: &Dir, name: &Path, directory: bool) -> io::Result<()> {
let metadata = parent.symlink_metadata(name)?;
if is_redirect(&metadata)
|| (directory && !metadata.is_dir())
|| (!directory && !metadata.is_file())
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"representation namespace entry is redirected or has the wrong type",
));
}
Ok(())
}
pub(in crate::engine::durable::representations) fn configure_no_follow(options: &mut OpenOptions) {
#[cfg(unix)]
{
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);View on GitHub (pinned to affd8760f4)