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

  1. Read the suffix after the colon for the real OS error and fix that (create the file, fix the path, or adjust permissions)
  2. Check `ls -l` on the reported filename to confirm existence and read permission
  3. Skip directories explicitly (`find . -type f | xargs cut ...`) instead of letting cut open them
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/bd174b69f945e421. Report an issue: GitHub.