Repository navigation
fix: handle StorageFull and I/O errors in Java world save instead of panicking - #787
Conversation
…panicking Replace all .expect()/.unwrap() calls in create_region, save_single_region, and save_java with proper error propagation. A Mutex captures the first error from the rayon parallel iterator; save() detects disk-full conditions and calls emit_gui_error() with a clear user-facing message instead of crashing.
|
⏱️ Benchmark run finished in 0m 26s 📈 Compared against baseline: 30s 🟢 Generation time is unchanged. 📅 Last benchmark: 2026-03-14 18:16:40 UTC You can retrigger the benchmark by commenting |
There was a problem hiding this comment.
Pull request overview
This PR improves robustness of Java world saving by replacing panic-based error handling with error propagation and user-facing messaging (especially for disk-full scenarios) during the final save step.
Changes:
- Convert
save_java,save_single_region, andcreate_regionto returnResultand propagate I/O/serialization errors instead ofunwrap/expect. - Capture the first error during rayon parallel region saving and return it after the parallel loop completes.
- In
WorldEditor::save(), detect disk-full situations and emit a GUI error/log message rather than crashing.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/world_editor/mod.rs |
Handles save_java() errors and emits a clearer user/GUI message for disk-full vs generic save failures. |
src/world_editor/java.rs |
Propagates errors from region creation and chunk writes; aggregates the first fatal error from parallel region saving. |
src/urban_ground.rs |
Reformats a geo import for readability (no logic changes). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… create_base_chunk Result, correct disk-full detection
- Replace lock().unwrap() with lock().unwrap_or_else(|p| p.into_inner()) on
all three Mutex accesses so a poisoned mutex never causes a secondary panic
- Add AtomicBool should_stop for lock-free fast-path early exit in the rayon
loop; the Mutex is now only acquired when actually storing the error value
- Change create_base_chunk to return Result and propagate the fastnbt
serialization error with ? instead of unwrap, closing the last panic hole
- Replace inline string-based disk-full detection with is_disk_full_error()
helper that walks the full error chain via .source(); fixes the 'code: 112'
pattern which never matched Windows io::Error Display ('os error 112')
There was a problem hiding this comment.
Pull request overview
This PR improves robustness of Java world saving by replacing panic-on-failure paths with error propagation and user-facing error reporting (notably for disk-full / I/O failures) during the final “save world” stage.
Changes:
- Added disk-full detection helper and GUI/telemetry error reporting when Java saving fails.
- Refactored Java Anvil saving helpers (
create_region,save_single_region,save_java) to returnResultand capture the first error from parallel region writes. - Reformatted a long
geoimport list for readability.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/world_editor/mod.rs |
Adds disk-full detection helper and handles save_java() failures without panicking, including GUI error emission. |
src/world_editor/java.rs |
Converts Java save pipeline to propagate errors instead of unwrap/expect, capturing first failure across rayon workers. |
src/urban_ground.rs |
Splits long geo import across multiple lines. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…isk_full_error correctness
Comment 2 (is_disk_full_error docstring/implementation mismatch):
- Walk source chain via .source() which yields &(dyn Error + 'static),
enabling downcast_ref::<io::Error>() for structured checks
- Check io_err.kind() == ErrorKind::StorageFull and raw_os_error() 112/28
as primary detection; keep Display string matching as fallback for
wrappers (e.g. fastanvil) that don't expose io::Error in source chain
- Fix docstring to accurately describe the hybrid approach
Comment 3 (HIGH - genuine regression: save() swallowed errors silently):
- Change save() from void to Result<(), Box<dyn Error + Send + Sync>>
- Return Err(e) after emitting the GUI error, so callers see the failure
- In data_processing.rs, propagate with if let Err(e) = editor.save() { return Err(...) }
- Previously: disk-full showed GUI error but pipeline continued to
'Finalizing world...' and returned Ok(output_path) - frontend saw success
Now: pipeline aborts cleanly on save failure
Skipped comment 1 (path context nit - no anyhow dependency, boilerplate cost
outweighs benefit for user-facing errors that already include OS message)
Skipped comment 4 (try_for_each style nit - AtomicBool approach is correct
and has a marginally better fast-path than try_for_each)
Replace all .expect()/.unwrap() calls in create_region, save_single_region, and save_java with proper error propagation. A Mutex captures the first error from the rayon parallel iterator; save() detects disk-full conditions and calls emit_gui_error() with a clear user-facing message instead of crashing.