{"record":{"id":"58ff8980ff02c995","repo":"GraphiteEditor/Graphite","slug":"failed-to-draw-the-circle","errorCode":null,"errorMessage":"Failed to draw the circle","messagePattern":"Failed to draw the circle","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"editor/src/messages/portfolio/document/overlays/utility_types_web.rs","lineNumber":431,"sourceCode":"\t\t\tlet dash_gap_width = dash_gap_width.unwrap_or(1.);\n\t\t\tlet array = js_sys::Array::new();\n\t\t\tarray.push(&JsValue::from(dash_width));\n\t\t\tarray.push(&JsValue::from(dash_gap_width));\n\n\t\t\tif let Some(dash_offset) = dash_offset {\n\t\t\t\tif dash_offset != 0. {\n\t\t\t\t\tself.render_context.set_line_dash_offset(dash_offset);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tself.render_context\n\t\t\t\t.set_line_dash(&JsValue::from(array))\n\t\t\t\t.map_err(|error| log::warn!(\"Error drawing dashed line: {:?}\", error))\n\t\t\t\t.ok();\n\t\t}\n\n\t\tself.render_context.begin_path();\n\t\tself.render_context.arc(position.x, position.y, radius, 0., TAU).expect(\"Failed to draw the circle\");\n\t\tself.render_context.set_stroke_style_str(color_stroke);\n\n\t\tif let Some(fill_color) = color_fill {\n\t\t\tself.render_context.set_fill_style_str(fill_color);\n\t\t\tself.render_context.fill();\n\t\t}\n\t\tself.render_context.stroke();\n\n\t\t// Reset the dash pattern back to solid\n\t\tif dash_width.is_some() {\n\t\t\tself.render_context\n\t\t\t\t.set_line_dash(&JsValue::from(js_sys::Array::new()))\n\t\t\t\t.map_err(|error| log::warn!(\"Error drawing dashed line: {:?}\", error))\n\t\t\t\t.ok();\n\t\t}\n\t\tif dash_offset.is_some() && dash_offset != Some(0.) {\n\t\t\tself.render_context.set_line_dash_offset(0.);\n\t\t}","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/overlays/utility_types_web.rs#L413-L449","documentation":"ctx.arc(position.x, position.y, radius, 0., TAU) maps to JS arc(), which throws IndexSizeError for a negative radius and can reject non-finite arguments. Unlike the constant-radius wrappers elsewhere in this file, radius is a caller-supplied parameter of dashed_circle, so bad geometry flows straight into the canvas API; the .expect turns the JS throw into a Rust panic.","triggerScenarios":"Any overlay caller passing a negative or NaN radius to dashed_circle — e.g., a size computed from a negative zoom scale, a half-extent of an inverted bound, or NaN propagated from document bounds.","commonSituations":"Handle/anchor radii scaled by zoom where the zoom math went negative or zero; layout arithmetic subtracting sizes into negative results; corrupted documents feeding non-finite bounds.","solutions":["Clamp radius at dashed_circle entry: skip drawing unless radius.is_finite() && radius >= 0.","Find the producer of the negative/NaN radius (zoom scale, bounds subtraction) and fix it at the source.","Degrade .expect to a logged if-let Err so one bad circle skips instead of crashing the overlay pass."],"exampleFix":"// before\nself.render_context.arc(position.x, position.y, radius, 0., TAU).expect(\"Failed to draw the circle\");\n\n// after\nif radius.is_finite() && radius >= 0. {\n\tif let Err(err) = self.render_context.arc(position.x, position.y, radius, 0., TAU) {\n\t\tlog::warn!(\"Failed to draw the circle: {:?}\", err);\n\t}\n}","handlingStrategy":"validation","validationCode":"fn circle_drawable(position: DVec2, radius: f64) -> bool {\n\tposition.x.is_finite() && position.y.is_finite() && radius.is_finite() && radius >= 0.\n}","typeGuard":"fn is_drawable_radius(radius: f64) -> bool {\n\tradius.is_finite() && radius >= 0.\n}","tryCatchPattern":"if let Err(err) = self.render_context.arc(position.x, position.y, radius, 0., TAU) {\n\tlog::warn!(\"overlay circle failed: {:?}\", err);\n}","preventionTips":["Clamp any caller-computed radius to non-negative finite values before it reaches dashed_circle","Check zoom-scale arithmetic for ways to go negative or zero","Never .expect on web_sys canvas calls in render loops — log and skip instead"],"tags":["wasm","canvas-2d","overlay","geometry","nan","panic"],"backgroundTag":"canvas-2d-negative-radius","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}