{"record":{"id":"8932d78f9f456da7","repo":"GraphiteEditor/Graphite","slug":"failed-to-draw-the-text-at-the-calculated-position","errorCode":null,"errorMessage":"Failed to draw the text at the calculated position","messagePattern":"Failed to draw the text at the calculated position","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"editor/src/messages/portfolio/document/overlays/utility_types_web.rs","lineNumber":1084,"sourceCode":"\t\t\tPivot::End => -padding,\n\t\t};\n\n\t\tlet [a, b, c, d, e, f] = (DAffine2::from_scale(DVec2::splat(self.viewport.scale())) * transform * DAffine2::from_translation(DVec2::new(x, y))).to_cols_array();\n\t\tself.render_context.set_transform(a, b, c, d, e, f).expect(\"Failed to rotate the render context to the specified angle\");\n\n\t\tif let Some(background) = background_color {\n\t\t\tself.render_context.set_fill_style_str(background);\n\t\t\tself.render_context.fill_rect(\n\t\t\t\t-padding,\n\t\t\t\tpadding,\n\t\t\t\tmetrics.actual_bounding_box_right() - metrics.actual_bounding_box_left() + padding * 2.,\n\t\t\t\tmetrics.font_bounding_box_descent() - metrics.font_bounding_box_ascent() - padding * 2.,\n\t\t\t);\n\t\t}\n\n\t\tself.render_context.set_font(r#\"12px \"Source Sans Pro\", Arial, sans-serif\"#);\n\t\tself.render_context.set_fill_style_str(font_color);\n\t\tself.render_context.fill_text(text, 0., 0.).expect(\"Failed to draw the text at the calculated position\");\n\t\tself.render_context.reset_transform().expect(\"Failed to reset the render context transform\");\n\t}\n\n\tpub fn translation_box(&mut self, translation: DVec2, quad: Quad, typed_string: Option<String>) {\n\t\tif translation.x.abs() > 1e-3 {\n\t\t\tself.dashed_line(quad.top_left(), quad.top_right(), None, None, Some(2.), Some(2.), Some(0.5));\n\n\t\t\tlet width = match typed_string {\n\t\t\t\tSome(ref typed_string) => typed_string,\n\t\t\t\tNone => &format_rounded(translation.x, 2),\n\t\t\t};\n\t\t\tlet x_transform = DAffine2::from_translation((quad.top_left() + quad.top_right()) / 2.);\n\t\t\tself.text(width, COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]);\n\t\t}\n\n\t\tif translation.y.abs() > 1e-3 {\n\t\t\tself.dashed_line(quad.top_left(), quad.bottom_left(), None, None, Some(2.), Some(2.), Some(0.5));\n","sourceCodeStart":1066,"sourceCodeEnd":1102,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/overlays/utility_types_web.rs#L1066-L1102","documentation":"After setting font and fill style, the overlay text routine calls fill_text(text, 0., 0.).expect(\"Failed to draw the text at the calculated position\"). fill_text is Result<(), JsValue> in wasm-bindgen; the spec does not have it throw for ordinary strings (non-finite coords are ignored), so this panic indicates the JS call itself threw - typically an invalidated or detached 2D context between measure_text and the draw, or a browser bug.","triggerScenarios":"Rendering any overlay label when the context becomes unusable between measure_text and fill_text within the same text() call, or the engine throwing on the prepared font/fill state.","commonSituations":"Canvas removed from DOM while overlays are mid-frame; context loss under GPU/memory pressure; rapid tab discard/restore during editing.","solutions":["Treat context loss as recoverable: detect the failure, rebuild the render context, and redraw on the next frame","Swap the expect for a logged if-let so text drawing degrades to a missing label rather than a WASM abort","Ensure the canvas backing the OverlayResource outlives every scheduled overlay render"],"exampleFix":"// before\nself.render_context.fill_text(text, 0., 0.).expect(\"Failed to draw the text at the calculated position\");\n\n// after\nif let Err(e) = self.render_context.fill_text(text, 0., 0.) {\n\tlog::error!(\"Failed to draw overlay text {text:?}: {e:?}\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(js_err) = self.render_context.fill_text(text, 0., 0.) {\n\tlog::error!(\"fill_text failed for {text:?}: {js_err:?}\");\n\t// still try to reset the transform so later overlays are unaffected\n\tlet _ = self.render_context.reset_transform();\n}","preventionTips":["Treat fill_text Err as context invalidation: rebuild the render context before the next frame","Always pair a failed draw with a transform reset so state does not leak to the next overlay","Ensure overlay drawing is cancelled when the backing canvas is removed from the DOM"],"tags":["rust","wasm-bindgen","canvas-2d","text-rendering","panic"],"backgroundTag":"canvas-2d-exception","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}