can1357/oh-my-pi · error
{}: {error}
Error message
{}: {error} What it means
When cut processes input files, any File::open failure is re-wrapped as io::Error with the message `<filename>: <underlying error>` (filename via maybe_quote). cut_files collects these per-file failures, marks the run failed, and cut_main reports the aggregate. The inner error is the real cause (ENOENT, EACCES, EISDIR, etc.).
Source
Thrown at crates/pi-builtins/src/cut.rs:745
fn cut_files<'a, I>(host: &mut Host, filenames: I, mode: &Mode)
where
I: IntoIterator<Item = &'a OsString>,
{
let inputs = filenames
.into_iter()
.map(|name| {
let path = if name == "-" { None } else { Some(host.resolve(name)) };
(name, path)
})
.collect::<Vec<_>>();
let mut stdin_read = false;
let mut failed = false;
let mut out = host.stdout_writer();
for (filename, path) in inputs {
let result = if let Some(path) = path {
File::open(path)
.map_err(|error| io::Error::new(error.kind(), format!("{}: {error}", filename.maybe_quote())))
.and_then(|file| match mode {
Mode::Bytes(ranges, opts) | Mode::Characters(ranges, opts) => {
cut_bytes(file, &mut out, ranges, opts)
},
Mode::Fields(ranges, opts) => cut_fields(file, &mut out, ranges, opts),
})
} else if stdin_read {
continue;
} else {
stdin_read = true;
match mode {
Mode::Bytes(ranges, opts) | Mode::Characters(ranges, opts) => {
cut_bytes(&mut host.stdin, &mut out, ranges, opts)
},
Mode::Fields(ranges, opts) => cut_fields(&mut host.stdin, &mut out, ranges, opts),
}
};
if let Err(error) = result {View on GitHub (pinned to 9690622007)
Solutions
- Read the suffix after the colon for the real OS error and fix that (create the file, fix the path, or adjust permissions)
- Check `ls -l` on the reported filename to confirm existence and read permission
- Skip directories explicitly (`find . -type f | xargs cut ...`) instead of letting cut open them
- Wrap cut_main invocation so per-file failures are logged while remaining files still process (cut already continues; check `failed` for exit status)
Example fix
// before cut -d: -f1 /etc/passwd.bak // ENOENT // after if [ -r /etc/passwd.bak ]; then cut -d: -f1 /etc/passwd.bak; else echo "missing" >&2; fi
Defensive patterns
Strategy: validation
Validate before calling
for f in files { let md = std::fs::metadata(f).map_err(|e| format!("{}: {}", f, e))?; if md.is_dir() { return Err(format!("{}: is a directory", f)); } } Try / catch
// cut already continues past failures; inspect the resultfor (filename, path) in inputs { if let Err(e) = open_and_cut(path) { eprintln!("cut: {}", e); failed = true; } }if failed { std::process::exit(1); } Prevention
- Check file existence and readability with test -r before feeding files to cut
- Exclude directories from generated file lists (find -type f)
- Re-check files that may be deleted concurrently; treat per-file errors as expected in pipelines
When it happens
Trigger: Calling `cut -d, -f1 missing.csv`, cutting a file without read permission, or passing a directory as an input file — any input path File::open rejects.
Common situations: Typos in filenames, files deleted between listing and processing in pipelines, scripts running as a user lacking permissions, or glob expansion passing directories to cut.
Related errors
- Permission denied
- Too many levels of symbolic links
- failed to create a unique fc temporary file
- 2
- dates before 1970 are unsupported
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/bd174b69f945e421.
Report an issue: GitHub.