a-b-street/abstreet · error
Couldn't read_dir
Error message
Couldn't read_dir {:?}: {} What it means
list_dir reads a directory and returns sorted full paths; it silently treats a missing directory as empty (NotFound), but any other read_dir failure panics with this message. Such errors mean the path exists but can't be read: permission problems, the path is a file not a directory, or an OS-level I/O error.
Solutions
- Check the path is a directory (Path::is_dir) and readable before calling list_dir.
- Fix permissions on the directory (chmod/chown) or run with appropriate access.
- If a NotFound should be tolerated, note list_dir already returns an empty Vec for that case; handle other Err kinds by pre-checking the path.
- Reproduce the underlying io::Error from the panic message and address it (e.g. replace the file-vs-directory path, remount a failed volume).
Example fix
// before
let files = abstio::list_dir("data/input".to_string());
// after
let dir = std::path::Path::new("data/input");
let files = if dir.is_dir() {
abstio::list_dir(dir.to_str().unwrap().to_string())
} else {
eprintln!("data/input is not a readable directory");
Vec::new()
}; Defensive patterns
Strategy: validation
Validate before calling
let dir = std::path::Path::new(&path);
if !dir.is_dir() {
eprintln!("{:?} is not a directory (list_dir only tolerates NotFound)", dir);
}
if !dir.is_dir() || std::fs::read_dir(dir).is_err() {
eprintln!("{:?} is not readable", dir);
} Type guard
fn is_readable_dir(path: &str) -> bool {
let p = std::path::Path::new(path);
p.is_dir() && std::fs::read_dir(p).is_ok()
} Try / catch
if !is_readable_dir(&dir_path) {
eprintln!("{:?} is not a readable directory", dir_path);
return Vec::new();
}
let files = abstio::list_dir(dir_path); Prevention
- Remember NotFound is tolerated (empty Vec) but every other error panics; pre-check is_dir for file-vs-directory mistakes.
- Check directory read permissions in container/sandbox setups before runs.
- Avoid scanning directories that may contain non-UTF-8 entry names (entry.unwrap() inside list_dir panics).
- Guard against network mounts going away mid-run; copy data locally when possible.
When it happens
Trigger: Calling list_dir(path) where the path is a regular file rather than a directory; the process lacks read permission on the directory; an OS I/O error occurs while iterating entries; also entry.unwrap() inside the loop panics on a bad directory entry (e.g. invalid UTF-8 path).
Common situations: Passing a file path where a directory was expected; sandboxed/containerized environments without permission on the data directory; scanning directories with entries whose names aren't valid UTF-8; NFS/network mounts returning transient I/O errors.
Related errors
- This build of A/B Street stores player data in…
- Can't find the data/ directory
- CityName::new( , ) has a country code that isn't two letters
- Couldn't read_json( )
- Couldn't read_binary
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/89c566176dee6dad.
Report an issue: GitHub.
Appendix: source
Thrown at abstio/src/io_native.rs:31
use abstutil::{elapsed_seconds, prettyprint_usize, to_json, Timer, PROGRESS_FREQUENCY_SECONDS};
pub use crate::io::*;
pub fn file_exists<I: AsRef<str>>(path: I) -> bool {
Path::new(path.as_ref()).exists()
}
/// Returns full paths
pub fn list_dir(path: String) -> Vec<String> {
let mut files: Vec<String> = Vec::new();
match fs_err::read_dir(&path) {
Ok(iter) => {
for entry in iter {
files.push(entry.unwrap().path().to_str().unwrap().to_string());
}
}
Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => panic!("Couldn't read_dir {:?}: {}", path, e),
};
files.sort();
files
}
pub fn slurp_file<I: AsRef<str>>(path: I) -> Result<Vec<u8>> {
inner_slurp_file(path.as_ref())
}
fn inner_slurp_file(path: &str) -> Result<Vec<u8>> {
|| -> Result<Vec<u8>> {
let mut file = File::open(path)?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?;
Ok(buffer)
}()
.with_context(|| path.to_string())
}
View on GitHub (pinned to 0964f29315)