EpicGames/lore · error · io::Error (InvalidInput)

not a regular file

Error message

not a regular file: {}

What it means

lore-storage's chunker `open_read` opens a path for reading and then verifies via the file's own metadata that it is a regular file. Directories, FIFOs, sockets, and device files are rejected with `ErrorKind::InvalidInput` and the offending path in the message. This prevents the chunker from streaming a directory handle or a special file and producing bogus chunk data.

Solutions

  1. Pass a regular file path instead of the directory/special file named in the message.
  2. Pre-check `metadata(path)?.is_file()` before calling `open_read` and skip non-files.
  3. If the path should be a directory, use the library's directory-walking API rather than opening it directly.

Example fix

// before
let (file, len) = chunker::open_read(user_path).await?;

// after
if !tokio::fs::metadata(user_path).await?.is_file() {
    eprintln!("skipping non-file: {}", user_path.display());
    return Ok(());
}
let (file, len) = chunker::open_read(user_path).await?;
Defensive patterns

Strategy: validation

Validate before calling

let meta = tokio::fs::metadata(path).await?;
if !meta.is_file() {
    anyhow::bail!("not a regular file: {}", path.display());
}

Try / catch

match chunker::open_read(path).await {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {
        eprintln!("skipping non-regular file: {}", path.display());
        Ok(())
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: Passing a directory or special file (fifo/socket/dev node) to `open_read`, `open_chunker`, or `streamed_chunks` — typically a user-supplied path that was never checked to be a file.

Common situations: Users pointing a tool at a directory instead of a file, a path that is a symlink to a directory, glob patterns that matched directories, or named pipes created by other tooling.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/484422e5129de998. Report an issue: GitHub.

Appendix: source

Thrown at lore-storage/src/chunker.rs:69

pub struct Chunk {
    pub offset: u64,
    pub data: Bytes,
}

/// Open `path` for reading, returning the shared handle and its size.
///
/// The size comes off the open handle rather than the path, so it describes the bytes about to be
/// read rather than what a separate stat of the path once saw. The same stat carries the file type,
/// so refusing anything but a regular file costs nothing beyond it — and has to happen here:
/// opening a directory read-only succeeds, and the size it reports is whatever the filesystem
/// chooses.
pub async fn open_read(path: &Path) -> std::io::Result<(IoFile, u64)> {
    let file = IoDriver::global()
        .open(path, &OpenOptions::new().read(true))
        .await?;
    let metadata = file.metadata().await?;
    if !metadata.is_file() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            format!("not a regular file: {}", path.display()),
        ));
    }
    Ok((file, metadata.len()))
}

/// How the chunker picks cut points.
enum CutMode {
    /// Cut where the content says to, matching whole-file `FastCDC`.
    ContentDefined,
    /// Cut every N bytes. Never exceeds [`FRAGMENT_SIZE_THRESHOLD`], so the window
    /// always holds at least one whole chunk.
    FixedSize(usize),
}

/// The window a read fills, owned by the operation for its whole flight and handed back
/// with it. A single segment: the read lands in `buffer[start..start + want]`, leaving

View on GitHub (pinned to 074eb0b0d1)