{"record":{"id":"314f64143aaecdea","repo":"louis-e/arnis","slug":"error-in-defining-coordinate-transformation-e","errorCode":null,"errorMessage":"Error in defining coordinate transformation:\n{e}","messagePattern":"Error in defining coordinate transformation:\n(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/osm_parser.rs","lineNumber":834,"sourceCode":"\n    // Deserialize the JSON data into the OSMData structure\n    let data = SplitOsmData::from_raw_osm_data(osm_data);\n\n    let (coord_transformer, xzbbox) = match projection {\n        crate::projection::ProjectionKind::WebMercator => {\n            let origin_lat = (bbox.min().lat() + bbox.max().lat()) / 2.0;\n            let origin_lon = (bbox.min().lng() + bbox.max().lng()) / 2.0;\n            let proj = crate::projection::WebMercatorProjection::new(origin_lat, origin_lon, scale);\n            CoordTransformer::with_projection(&bbox, scale, &proj)\n        }\n        crate::projection::ProjectionKind::Local => {\n            CoordTransformer::llbbox_to_xzbbox(&bbox, scale)\n        }\n    }\n    // Panics rather than exits: the GUI calls this from a Tauri blocking task, where an\n    // exit would take the whole app down. Bad scales are rejected up front by validate_scale.\n    .unwrap_or_else(|e| {\n        panic!(\"Error in defining coordinate transformation:\\n{e}\");\n    });\n\n    if debug {\n        println!(\"Total elements: {}\", data.total_count());\n        println!(\"Scale factor X: {}\", coord_transformer.scale_factor_x());\n        println!(\"Scale factor Z: {}\", coord_transformer.scale_factor_z());\n    }\n\n    let mut part_groups = PartGroups::new();\n    let mut outline_suppression =\n        compute_outline_suppression(&data.relations, &data.ways, &data.nodes, &mut part_groups);\n    // Ways owned by a type=building relation are handled above; the spatial pass must\n    // not re-judge them against unrelated parts that merely fall inside their footprint.\n    let relation_ways: HashSet<u64> = data\n        .relations\n        .iter()\n        .filter(|r| {\n            r.tags","sourceCodeStart":816,"sourceCodeEnd":852,"githubUrl":"https://github.com/louis-e/arnis/blob/34048924d9365795fb0d832e76140a3fbdc413d9/src/osm_parser.rs#L816-L852","documentation":"parse_osm_data builds a CoordTransformer via llbbox_to_xzbbox (or a variant) to convert lat/lon bounding boxes into Minecraft x/z coordinates. If the coordinate transformation cannot be defined — the underlying proj/geodesic computation fails or the resulting transform is invalid — the Result is Err and the code deliberately panics with 'Error in defining coordinate transformation:\\n{e}'. It panics instead of exiting because the GUI invokes this from a Tauri blocking task, where process::exit would kill the whole app; invalid scales are rejected earlier by validate_scale.","triggerScenarios":"Calling parse_osm_data with a bbox that produces a degenerate/invalid transform (zero-size or inverted min/max coordinates, coordinates outside valid lat/lon ranges like lat > 90 or NaN), or with values that slip past validate_scale (e.g. calling the API directly from the GUI command without validating scale first).","commonSituations":"Hand-edited or GUI-supplied bbox strings like \"a,b,c,d\" partially parsed into weird floats; swapped min/max lat/lon yielding a negative-size box; programmatically generated bboxes containing NaN/inf; calling the library path directly and skipping validate_scale.","solutions":["Validate the bbox before calling: min_lat < max_lat, min_lon < max_lon, all values finite, lat within [-90,90], lon within [-180,180]","Run validate_scale on the scale argument first (the parser assumes it was already applied)","Check the panic message's {e} body — it contains the underlying transformer error naming the bad parameter","Sanitize/parse bbox input strictly (reject NaN, inf, non-numeric tokens) at the CLI/GUI boundary","If hit from the GUI, the panic is caught by the Tauri blocking-task handling; report and fix the input values that were passed in"],"exampleFix":"// before: unvalidated input from user string\nlet bbox = parse_bbox(&args.bbox).unwrap();\nosm_parser::parse_osm_data(&data, &bbox, scale, debug);\n// after: validate before transforming\nlet bbox = parse_bbox(&args.bbox)?;\nassert!(bbox.min_lat < bbox.max_lat && bbox.min_lon < bbox.max_lon,\n        \"bbox must be min,max ordered and finite\");\nvalidate_scale(scale)?;\nosm_parser::parse_osm_data(&data, &bbox, scale, debug);","handlingStrategy":"validation","validationCode":"fn bbox_is_valid(bbox: &LLBBox) -> bool {\n    bbox.min_lat < bbox.max_lat\n        && bbox.min_lon < bbox.max_lon\n        && bbox.min_lat >= -90.0 && bbox.max_lat <= 90.0\n        && bbox.min_lon >= -180.0 && bbox.max_lon <= 180.0\n        && [bbox.min_lat, bbox.max_lat, bbox.min_lon, bbox.max_lon]\n            .iter().all(|v| v.is_finite())\n}\n// also: validate_scale(scale)?; before calling parse_osm_data","typeGuard":null,"tryCatchPattern":"// Rust: catch the panic when calling from the GUI blocking task\nlet result = std::panic::catch_unwind(|| {\n    osm_parser::parse_osm_data(&data, &bbox, scale, debug)\n});\nmatch result {\n    Ok(parsed) => parsed,\n    Err(p) => emit_gui_error(\"Invalid bbox/scale: coordinate transform failed\")\n}","preventionTips":["Always validate the bbox (ordered, finite, in-range) before parsing","Run validate_scale on every scale before it reaches parse_osm_data","Sanitize user/GUI input strictly: reject NaN, inf, and malformed bbox strings","When calling the library directly, never skip the validation the CLI front-end performs","Read the {e} in the panic message — it pinpoints the offending parameter"],"tags":["coordinates","projection","panic","rust","validation"],"backgroundTag":"coordinate-transform-failed","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"}