can1357/oh-my-pi · error · WcError

{context}: {source}

Error message

{context}: {source}

What it means

WcError::Io { context, source } is wc's contextual IO error: it prefixes an io::Error with what wc was doing (`{context}: {source}`) and keeps the original as #[source]. The context tells you which phase failed (opening, reading, or stat-ing a file) while the source carries the errno-level cause.

Source

Thrown at crates/pi-builtins/src/wc.rs:793

		match self {
			Self::Auto => num_inputs > 1,
			Self::Always | Self::Only => true,
			Self::Never => false,
		}
	}
}

#[derive(Debug, Error)]
enum WcError {
	#[error("extra operand {}\nfile operands cannot be combined with --files0-from", extra.quote())]
	FilesDisabled { extra: Cow<'static, OsStr> },
	#[error("when reading file names from standard input, no file name of '-' allowed")]
	StdinReprNotAllowed,
	#[error("invalid zero-length file name")]
	ZeroLengthFileName,
	#[error("{path}:{idx}: invalid zero-length file name")]
	ZeroLengthFileNameCtx { path: Cow<'static, str>, idx: usize },
	#[error("{context}: {source}")]
	Io {
		context: String,
		#[source]
		source:  io::Error,
	},
}

impl WcError {
	fn zero_len(ctx: Option<(&Input, usize)>) -> Self {
		match ctx {
			Some((input, idx)) => {
				let path = match input {
					Input::Stdin(_) => STDIN_REPR.into(),
					Input::Path(path) => escape_name_wrapper(path.as_os_str()).into(),
				};
				Self::ZeroLengthFileNameCtx { path, idx }
			},
			None => Self::ZeroLengthFileName,

View on GitHub (pinned to 9690622007)

Solutions

  1. Read `context` to see which file/operation failed, then the `source` errno for the cause
  2. Check existence and permissions of the reported path (ls -l, or run as a user with access)
  3. Skip unreadable inputs and continue with the remaining files in the list
  4. For ENOENT, correct the path or regenerate the file list from a current find/ls

Example fix

// context: "a.log: read" source: Permission denied (os error 13)
// after
for f in files {
    if let Err(e) = std::fs::File::open(f) {
        if e.kind() == std::io::ErrorKind::PermissionDenied {
            eprintln!("skipping unreadable: {f}");
            continue;
        }
        return Err(e.into());
    }
    // process f
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn wc_inputs_ok(paths: &[std::path::PathBuf]) -> Vec<(std::path::PathBuf, std::io::Error)> {
    paths.iter()
        .filter_map(|p| std::fs::File::open(p).err().map(|e| (p.clone(), e)))
        .collect()
}

Try / catch

match result {
    Err(WcError::Io { context, source }) => {
        eprintln!("{context}: {source}");
        if source.kind() == std::io::ErrorKind::NotFound {
            // regenerate or drop the missing input
        } else if source.kind() == std::io::ErrorKind::PermissionDenied {
            // skip and continue with remaining files
        }
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: Any io::Error during wc's per-file processing — open() failing with EACCES/ENOENT, read() failing mid-stream, or metadata() failing — wrapped with the file-specific context string.

Common situations: wc on a nonexistent or misspelled path (ENOENT); unreadable files under another user (EACCES); reading special files with unusual semantics; disk/device errors on large inputs.

Related errors


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