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
- Read the wrapped io::Error's errno for the root cause
- Check for symlink loops or I/O problems on the target path
- Retry if the error is transient (EIO/EMFILE) or raise the fd limit
- 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
- Probe paths with metadata before listing
- Watch for symlink loops (ELOOP) and transient errors (EIO) on network mounts
- Raise the fd limit when recursing very large trees
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
- Too many levels of symbolic links
- {}: {error}
- failed to create a unique fc temporary file
- 2
- cannot access {}: Not a directory
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/923c1f0f04dbea4a.
Report an issue: GitHub.