affaan-m/ECC · error
{label} must be a regular file
Error message
{label} must be a regular file What it means
Runtime error from a bounded-file reader in ecc2/src/main.rs. After opening `path` (with O_NONBLOCK on unix) and reading metadata, the code checks metadata.is_file(); if the path is not a regular file it bails with "{label} must be a regular file", where `label` names the input (e.g. a flag like --patch or --input). The check excludes directories, devices, sockets, pipes, and non-regular specials, so the input cannot be streamed or stat'd as bytes.
Source
Thrown at ecc2/src/main.rs:1409
details: BTreeMap<String, String>,
}
fn read_bounded_file(path: &Path, max_bytes: u64, label: &str) -> Result<Vec<u8>> {
let mut options = File::options();
options.read(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
options.custom_flags(libc::O_NONBLOCK);
}
let file = options
.open(path)
.with_context(|| format!("Failed to open {}", path.display()))?;
let metadata = file
.metadata()
.with_context(|| format!("Failed to inspect {}", path.display()))?;
if !metadata.is_file() {
anyhow::bail!("{label} must be a regular file");
}
let read_limit = max_bytes
.checked_add(1)
.context("bounded input byte limit is too large")?;
let mut content = Vec::new();
file.take(read_limit)
.read_to_end(&mut content)
.with_context(|| format!("Failed to read {}", path.display()))?;
if content.len() as u64 > max_bytes {
anyhow::bail!("{label} exceeds the {max_bytes}-byte limit");
}
Ok(content)
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()View on GitHub (pinned to 01e15490f0)
Solutions
- Point the flag at an actual file path; verify with ls -l / stat.
- If you intended stdin, check whether the command supports - as a sentinel; otherwise write to a temp file first.
- Resolve symlinks (readlink -f) to confirm the target is a regular file.
- Avoid passing device nodes or pipes to flags that require regular files.
Example fix
# before $ ecc cmd --patch ./patches/ # after $ ecc cmd --patch ./patches/0001-fix.patch
Defensive patterns
Strategy: validation
Validate before calling
// Verify regular-file-ness before invoking the bounded reader.
use std::fs;
fn assert_regular_file(label: &str, path: &Path) -> Result<()> {
let meta = fs::symlink_metadata(path)?;
if meta.file_type().is_symlink() {
let target = fs::metadata(path)?;
anyhow::ensure!(target.is_file(), "{label} must be a regular file");
} else {
anyhow::ensure!(meta.is_file(), "{label} must be a regular file");
}
Ok(())
} Type guard
fn is_regular_file(path: &Path) -> bool {
fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
} Try / catch
let content = read_bounded(label, path, max_bytes).map_err(|e| {
if e.to_string().contains("must be a regular file") {
anyhow::anyhow!("{e}; pass a file path, not a directory or device")
} else {
e
}
})?; Prevention
- Pre-check paths with fs::metadata before passing to bounded readers.
- Resolve symlinks (fs::canonicalize) and re-check before use.
- Avoid device nodes and named pipes for inputs that must be regular files.
- Validate at the CLI parser with value parsers when possible.
When it happens
Trigger: Passing a path to a bounded-input flag where the path resolves to a directory, FIFO, device, socket, or symlink whose target is not a regular file. The open succeeds but metadata().is_file() returns false.
Common situations: User passed a directory path by mistake; a symlink points at a directory; /dev/null or /dev/stdin used where a regular file is required; a named pipe created by another process; a glob expanded to a directory.
Related errors
- --config-dir must exist and contain a regular sixtytwo.yaml
- ${EXECUTABLE_OVERRIDE} does not point to a readable local It
- {label} exceeds the {max_bytes}-byte limit
- Multiple ECC repo roots detected: ${uniqueRepoRoots.join(',
- TypeScript compiler not found. Install root dev dependencies
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/9c7fdd8e8a8c66ad.
Report an issue: GitHub.