astrid-runtime/astrid · error · io::Error

opened representation entry is redirected or not a regular f

Error message

opened representation entry is redirected or not a regular file

What it means

validate_opened_regular stats an already-opened representation File and rejects it if it is not a regular file or if opened_file_is_redirected reports redirection (e.g. opened via /proc-style magic link). This InvalidData error ensures the handle the library holds truly refers to a regular file at open time.

Source

Thrown at crates/astrid-storage/src/engine/durable/representations/contiguous/namespace.rs:121

    #[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);
    }
}

pub(in crate::engine::durable::representations) fn validate_opened_regular(
    file: &File,
) -> io::Result<()> {
    let metadata = file.metadata()?;
    if !metadata.is_file() || opened_file_is_redirected(&metadata) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "opened representation entry is redirected or not a regular file",
        ));
    }
    Ok(())
}

#[cfg(windows)]
fn opened_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 opened_file_is_redirected(_metadata: &std::fs::Metadata) -> bool {
    false

View on GitHub (pinned to affd8760f4)

Solutions

  1. Reopen the file after the racing writer has finished; the validation passes on a stable file
  2. Eliminate concurrent processes that replace representation files during reads/writes
  3. Use the library's locking or a single-owner process model for the store
  4. Audit for symlink/magic-link exposure of the store path and block it at the filesystem level

Example fix

// before
fs::write("store/rep/f", data) // another job replaces f with a fifo mid-open
// after
exclusive_lock(store); write; unlock
Defensive patterns

Strategy: retry

Validate before calling

// verify path target before opening
let md = path.symlink_metadata()?;
if !md.is_file() { return Err("representation entry is not a regular file"); }

Try / catch

match open_file_result {
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        // likely a swap race; wait for writer completion and reopen
        std::thread::sleep(Duration::from_millis(50));
        open_file(path)
    }
    r => r,
}

Prevention

When it happens

Trigger: Calling open_file on an entry that was swapped to a non-regular object between path validation and open, or opened through a redirection (e.g. O_PATH/magic-link tricks) so metadata on the handle reports a non-file.

Common situations: TOCTOU races with concurrent deletion/recreation of representation files; exploits using magic symlinks to redirect opens; corrupted namespace entries pointing at devices or FIFOs.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/f1d61e9e94b7a2bf. Report an issue: GitHub.