{"record":{"id":"eb1060c5b0b302fe","repo":"a-b-street/abstreet","slug":"can-t-write-json","errorCode":null,"errorMessage":"Can't write_json({}): {}","messagePattern":"Can't write_json\\((.+?)\\): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"abstio/src/io_native.rs","lineNumber":74,"sourceCode":"    bincode::deserialize_from(timer).map_err(|err| err.into())\n}\n\n// TODO Idea: Have a wrapper type DotJSON(...) and DotBin(...) to distinguish raw path strings\nfn maybe_write_json<T: Serialize>(path: &str, obj: &T) -> Result<()> {\n    if !path.ends_with(\".json\") {\n        panic!(\"write_json needs {} to end with .json\", path);\n    }\n    fs_err::create_dir_all(std::path::Path::new(path).parent().unwrap())\n        .expect(\"Creating parent dir failed\");\n\n    let mut file = File::create(path)?;\n    file.write_all(to_json(obj).as_bytes())?;\n    Ok(())\n}\n\npub fn write_json<T: Serialize>(path: String, obj: &T) {\n    if let Err(err) = maybe_write_json(&path, obj) {\n        panic!(\"Can't write_json({}): {}\", path, err);\n    }\n    info!(\"Wrote {}\", path);\n}\n\nfn maybe_write_binary<T: Serialize>(path: &str, obj: &T) -> Result<()> {\n    if !path.ends_with(\".bin\") {\n        panic!(\"write_binary needs {} to end with .bin\", path);\n    }\n\n    fs_err::create_dir_all(std::path::Path::new(path).parent().unwrap())\n        .expect(\"Creating parent dir failed\");\n\n    let file = BufWriter::new(File::create(path)?);\n    bincode::serialize_into(file, obj).map_err(|err| err.into())\n}\n\npub fn write_binary<T: Serialize>(path: String, obj: &T) {\n    if let Err(err) = maybe_write_binary(&path, obj) {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/abstio/src/io_native.rs#L56-L92","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nabstio::write_json(\"/mnt/ro/output/stats.json\".to_string(), &stats);\n\n// after\nlet path = \"/mnt/ro/output/stats.json\";\nif std::path::Path::new(path).parent().map_or(false, |d| d.is_dir()) {\n    abstio::write_json(path.to_string(), &stats);\n} else {\n    eprintln!(\"skipping write: {} is not writable\", path);\n}","handlingStrategy":"validation","validationCode":"let p = std::path::Path::new(&path);\nif !path.ends_with(\".json\") {\n    eprintln!(\"write_json requires .json extension: {}\", path);\n}\nif let Some(parent) = p.parent() {\n    if !parent.is_dir() {\n        eprintln!(\"parent dir {:?} missing\", parent);\n    }\n}","typeGuard":"fn is_writable_json_path(path: &str) -> bool {\n    let p = std::path::Path::new(path);\n    path.ends_with(\".json\")\n        && p.parent().map_or(false, |d| d.is_dir())\n        && std::fs::OpenOptions::new().write(true).create(true).open(p).is_ok()\n}","tryCatchPattern":"// write_json panics; probe writability first or use a Result-returning writer:\nmatch std::fs::File::create(&path) {\n    Ok(_) => abstio::write_json(path.clone(), &obj),\n    Err(e) => eprintln!(\"can't write {}: {}\", path, e),\n}","preventionTips":["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."],"tags":["rust","panic","serialization","file-io"],"backgroundTag":"file-write-failed","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}