a-b-street/abstreet · error
Can't write_json( )
Error message
Can't write_json({}): {} What it means
write_json serializes obj to JSON and writes it to path, panicking with this message if any I/O step fails. Note that a path not ending in .json causes a different panic inside maybe_write_json ('write_json needs ... to end with .json'), and parent-directory creation failure panics separately. This specific panic fires on File::create or write_all errors from fs_err.
Solutions
- Verify the parent directory is writable and the filesystem isn't read-only or full (df, mount flags).
- Check the path ends with .json and its parent is a valid directory before calling.
- If failure should be tolerable, call maybe_write_json-equivalent by using abstio::write_file or handle Result-returning APIs instead.
- Fix permissions (chmod/chown) on the output directory or run with an account that can write there.
Example fix
// before
abstio::write_json("/mnt/ro/output/stats.json".to_string(), &stats);
// after
let path = "/mnt/ro/output/stats.json";
if std::path::Path::new(path).parent().map_or(false, |d| d.is_dir()) {
abstio::write_json(path.to_string(), &stats);
} else {
eprintln!("skipping write: {} is not writable", path);
} Defensive patterns
Strategy: validation
Validate before calling
let p = std::path::Path::new(&path);
if !path.ends_with(".json") {
eprintln!("write_json requires .json extension: {}", path);
}
if let Some(parent) = p.parent() {
if !parent.is_dir() {
eprintln!("parent dir {:?} missing", parent);
}
} Type guard
fn is_writable_json_path(path: &str) -> bool {
let p = std::path::Path::new(path);
path.ends_with(".json")
&& p.parent().map_or(false, |d| d.is_dir())
&& std::fs::OpenOptions::new().write(true).create(true).open(p).is_ok()
} Try / catch
// write_json panics; probe writability first or use a Result-returning writer:
match std::fs::File::create(&path) {
Ok(_) => abstio::write_json(path.clone(), &obj),
Err(e) => eprintln!("can't write {}: {}", path, e),
} Prevention
- Always end output paths with .json; other extensions panic in maybe_write_json.
- Confirm the output filesystem is not read-only (common in containers/CI).
- Monitor free disk space for long-running jobs that write many JSON files.
- Run as a user with write permission on the output directory.
When it happens
Trigger: Calling write_json(path, obj) where the target file cannot be created (read-only filesystem, permission denied, invalid path) or cannot be fully written (disk full, I/O error, broken pipe when writing to special files).
Common situations: Writing to a read-only output directory or container filesystem; disk quota/full disk on long runs; path components that aren't valid; output paths mounted from a volume without write permission.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Can't write_binary( )
- Couldn't read_json( )
- Couldn't read_binary
- Couldn't read_object
- Compressed not there?
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/eb1060c5b0b302fe.
Report an issue: GitHub.
Appendix: source
Thrown at abstio/src/io_native.rs:74
bincode::deserialize_from(timer).map_err(|err| err.into())
}
// TODO Idea: Have a wrapper type DotJSON(...) and DotBin(...) to distinguish raw path strings
fn maybe_write_json<T: Serialize>(path: &str, obj: &T) -> Result<()> {
if !path.ends_with(".json") {
panic!("write_json needs {} to end with .json", path);
}
fs_err::create_dir_all(std::path::Path::new(path).parent().unwrap())
.expect("Creating parent dir failed");
let mut file = File::create(path)?;
file.write_all(to_json(obj).as_bytes())?;
Ok(())
}
pub fn write_json<T: Serialize>(path: String, obj: &T) {
if let Err(err) = maybe_write_json(&path, obj) {
panic!("Can't write_json({}): {}", path, err);
}
info!("Wrote {}", path);
}
fn maybe_write_binary<T: Serialize>(path: &str, obj: &T) -> Result<()> {
if !path.ends_with(".bin") {
panic!("write_binary needs {} to end with .bin", path);
}
fs_err::create_dir_all(std::path::Path::new(path).parent().unwrap())
.expect("Creating parent dir failed");
let file = BufWriter::new(File::create(path)?);
bincode::serialize_into(file, obj).map_err(|err| err.into())
}
pub fn write_binary<T: Serialize>(path: String, obj: &T) {
if let Err(err) = maybe_write_binary(&path, obj) {View on GitHub (pinned to 0964f29315)