{"record":{"id":"42ddf1613d8d632e","repo":"louis-e/arnis","slug":"elevation-data-not-available","errorCode":null,"errorMessage":"Elevation data not available","messagePattern":"Elevation data not available","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/ground.rs","lineNumber":914,"sourceCode":"                };\n                img.put_pixel(x as u32, z as u32, color);\n            }\n        }\n        let filename: String = if !filename.ends_with(\".png\") {\n            format!(\"{filename}.png\")\n        } else {\n            filename.to_string()\n        };\n        if let Err(e) = img.save(&filename) {\n            eprintln!(\"Failed to save canopy debug image: {e}\");\n        }\n    }\n\n    fn save_debug_image(&self, filename: &str) {\n        let heights = &self\n            .elevation_data\n            .as_ref()\n            .expect(\"Elevation data not available\")\n            .heights;\n        if heights.is_empty() || heights[0].is_empty() {\n            return;\n        }\n\n        let height: usize = heights.len();\n        let width: usize = heights[0].len();\n        let mut img: image::ImageBuffer<Rgb<u8>, Vec<u8>> =\n            RgbImage::new(width as u32, height as u32);\n\n        let mut min_height: f32 = f32::MAX;\n        let mut max_height: f32 = f32::MIN;\n\n        for row in heights {\n            for &h in row {\n                if h.is_finite() {\n                    min_height = min_height.min(h);\n                    max_height = max_height.max(h);","sourceCodeStart":896,"sourceCodeEnd":932,"githubUrl":"https://github.com/louis-e/arnis/blob/34048924d9365795fb0d832e76140a3fbdc413d9/src/ground.rs#L896-L932","documentation":"save_debug_image unconditionally expects self.elevation_data to be Some, unwrapping it with .expect. If the ground generator ran without elevation data (provider failed, disabled, or not yet loaded), the Option is None and this panic fires. Notably it is raised in a debug-image helper invoked from generate_ground_data, so a missing-elevation condition surfaces as an unrelated-looking panic during generation.","triggerScenarios":"generate_ground_data calls save_debug_image while self.elevation_data is None — i.e. elevation data was never assigned because the elevation provider failed or was skipped, and the debug-image path was enabled.","commonSituations":"Debug image output enabled in config while elevation fetching failed silently or was disabled; calling generate_ground_data before elevation data finished loading; a refactor that made elevation_data optional without updating the debug-image path.","solutions":["Make save_debug_image take the elevation data as a parameter or return early (log a warning) when elevation_data is None, instead of expect-ing.","Fix the root cause: ensure generate_ground_data either has elevation data or skips elevation-dependent debug output when it is absent.","If elevation data is required, fail generate_ground_data with a clear 'elevation data unavailable' error before doing any work."],"exampleFix":"// before\nlet heights = &self.elevation_data.as_ref().expect(\"Elevation data not available\").heights;\n// after\nlet Some(elevation) = self.elevation_data.as_ref() else {\n    eprintln!(\"save_debug_image: skipped, no elevation data\");\n    return;\n};\nlet heights = &elevation.heights;","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn has_elevation(g: &GroundData) -> bool { g.elevation_data.is_some() }","tryCatchPattern":"// Rust panic; avoid by narrowing first\nif let Some(elevation) = &self.elevation_data {\n    self.write_debug_image(filename, &elevation.heights);\n} else {\n    log::warn!(\"save_debug_image skipped: no elevation data\");\n}","preventionTips":["Skip elevation-dependent debug output when elevation_data is None","Surface elevation provider failures explicitly instead of leaving the field None","Test generate_ground_data with elevation disabled to ensure no hidden panics"],"tags":["panic","missing-data","elevation","debug"],"backgroundTag":"unwrap-on-none","analyzedSha":"34048924d9365795fb0d832e76140a3fbdc413d9","analyzedAt":"2026-09-03T14:05:17.283Z","contentChangedAt":"2026-09-03T14:05:17.283Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}