quickwit-oss/quickwit · error · StorageError

file `{}` is not a regular file, cannot determine its size

Error message

file `{}` is not a regular file, cannot determine its size

What it means

`file_num_bytes` on LocalFileStorage stats the path with `tokio::fs::metadata` and refuses to return a size if the target is not a regular file (directory, fifo, socket, device). It maps that case to a NotFound StorageError rather than returning a meaningless byte count.

Source

Thrown at quickwit/quickwit-storage/src/local_file_storage.rs:350

    }

    fn uri(&self) -> &Uri {
        &self.uri
    }

    #[tracing::instrument(
        name = "storage.local_file.file_num_bytes",
        level = "debug",
        skip(self)
    )]
    async fn file_num_bytes(&self, path: &Path) -> StorageResult<u64> {
        let full_path = self.full_path(path)?;
        match tokio::fs::metadata(full_path).await {
            Ok(metadata) => {
                if metadata.is_file() {
                    Ok(metadata.len())
                } else {
                    Err(StorageErrorKind::NotFound.with_error(anyhow::anyhow!(
                        "file `{}` is not a regular file, cannot determine its size",
                        path.display()
                    )))
                }
            }
            Err(err) => {
                if err.kind() == ErrorKind::NotFound {
                    Err(StorageErrorKind::NotFound.with_error(err))
                } else {
                    Err(err.into())
                }
            }
        }
    }
}

/// A File storage resolver
#[derive(Clone, Debug, Default)]

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Verify the path points to an actual file, not a directory (`file <path>` or `ls -l`)
  2. Correct the index/storage URI in the config so it references files, not directories
  3. If a symlink is involved, confirm it resolves to a regular file
  4. Handle the NotFound StorageErrorKind in the caller if probing optional paths

Example fix

// before
let size = storage.file_num_bytes(&dir_path).await?;
// after
if tokio::fs::metadata(&dir_path).await.map(|m| m.is_file()).unwrap_or(false) {
    let size = storage.file_num_bytes(&dir_path).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

let md = tokio::fs::metadata(&path).await?;
if !md.is_file() {
    return Err(anyhow::anyhow!("{} is not a regular file", path.display()));
}
let expected_len = md.len();

Type guard

fn is_regular_file(md: &std::fs::Metadata) -> bool { md.is_file() }

Try / catch

match storage.file_num_bytes(&path).await {
    Ok(len) => use(len),
    Err(e) if e.kind() == StorageErrorKind::NotFound => skip_or_recreate(path),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `Storage::file_num_bytes` (or APIs that stat objects, e.g. delete/list flows using sizes) with a path that resolves to a directory or special file instead of a regular file.

Common situations: Misconfigured index URI pointing at a directory instead of the index root's files; a path that was expected to be a file but is a symlink target that became a directory; passing a prefix/directory path to a size-query API.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/744764c8cc310b1a. Report an issue: GitHub.