can1357/oh-my-pi · error · LsError

1

1

Error message

general io error: {0}

What it means

The ls builtin's IOError variant wraps a std::io::Error via #[from] as a generic fallback for filesystem failures not covered by the specialized cannot-access variant. It is displayed as 'general io error: {os error}' and exits with code 1.

Source

Thrown at crates/pi-builtins/src/ls.rs:3680

fn write_os_str<W: Write>(writer: &mut W, string: &OsStr) -> std::io::Result<()> {
	writer.write_all(&os_bytes_lossy(string))
}
}

use colors::StyleManager;
pub use config::{Config, options};
use config::{Dereference, Files, Sort, options::QUOTING_STYLE};
use dired::DiredOutput;
pub use display::Format;
use display::{display_items, display_size, should_display, show_dir_name};

#[derive(Error, Debug)]
enum LsError {
	#[error("invalid line width: '{0}'")]
	InvalidLineWidth(String),

	#[error("general io error: {0}")]
	IOError(#[from] std::io::Error),

	#[error("{}", match .1.kind() {
		ErrorKind::NotADirectory => format!("cannot access {}: Not a directory", .0.quote()),
		ErrorKind::NotFound => format!("cannot access {}: No such file or directory", .0.quote()),
		ErrorKind::PermissionDenied => match .1.raw_os_error().unwrap_or(1) {
			1 => format!("cannot access {}: Operation not permitted", .0.quote()),
			_ => if *.3 {
				format!("cannot open directory {}: Permission denied", .0.quote())
			} else {
				format!("cannot open file {}: Permission denied", .0.quote())
			},
		},
		_ => if 9 == .1.raw_os_error().unwrap_or(1) {
			format!("cannot open directory {}: Bad file descriptor", .0.quote())
		} else {
			format!("unknown io error: {}, '{:?}'", .0.quote(), .1)
		},

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the wrapped io::Error's errno for the root cause
  2. Check for symlink loops or I/O problems on the target path
  3. Retry if the error is transient (EIO/EMFILE) or raise the fd limit
  4. Run ls on a subset of paths to isolate the failing one

Example fix

// before
ls(&host, &["/mnt/flaky"])?;
// after
match ls(&host, &["/mnt/flaky"]) {
    Err(e) if e.kind() == std::io::ErrorKind::Interrupted => retry_ls(),
    other => other?,
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn check_path_accessible(p: &Path) -> std::io::Result<()> {
    std::fs::metadata(p).map(|_| ( ))
}

Try / catch

match ls(&host, args) {
    Err(e) => match e.downcast_ref::<std::io::Error>() {
        Some(io) => eprintln!("ls io failure (kind={:?}): {io}", io.kind()),
        None => return Err(e),
    },
    ok => ok?,
}

Prevention

When it happens

Trigger: Directory reads or metadata calls failing with io errors other than NotADirectory/NotFound/PermissionDenied (e.g. ELOOP, EIO, EMFILE) while ls walks the path arguments.

Common situations: Broken symlink loops, failing disks, file-descriptor exhaustion when listing huge directory trees, odd filesystem errors on network mounts.

Understand the failure class

Background: Rust io::Error: what ErrorKind::NotFound, PermissionDenied, and InvalidData actually mean — from real OS failures to library fail-closed refusals — this error's family across 12 libraries.

Related errors


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