GraphiteEditor/Graphite · error

Failed to draw the text at the calculated position

Error message

Failed to draw the text at the calculated position

What it means

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.

Source

Thrown at editor/src/messages/portfolio/document/overlays/utility_types_web.rs:1084

			Pivot::End => -padding,
		};

		let [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();
		self.render_context.set_transform(a, b, c, d, e, f).expect("Failed to rotate the render context to the specified angle");

		if let Some(background) = background_color {
			self.render_context.set_fill_style_str(background);
			self.render_context.fill_rect(
				-padding,
				padding,
				metrics.actual_bounding_box_right() - metrics.actual_bounding_box_left() + padding * 2.,
				metrics.font_bounding_box_descent() - metrics.font_bounding_box_ascent() - padding * 2.,
			);
		}

		self.render_context.set_font(r#"12px "Source Sans Pro", Arial, sans-serif"#);
		self.render_context.set_fill_style_str(font_color);
		self.render_context.fill_text(text, 0., 0.).expect("Failed to draw the text at the calculated position");
		self.render_context.reset_transform().expect("Failed to reset the render context transform");
	}

	pub fn translation_box(&mut self, translation: DVec2, quad: Quad, typed_string: Option<String>) {
		if translation.x.abs() > 1e-3 {
			self.dashed_line(quad.top_left(), quad.top_right(), None, None, Some(2.), Some(2.), Some(0.5));

			let width = match typed_string {
				Some(ref typed_string) => typed_string,
				None => &format_rounded(translation.x, 2),
			};
			let x_transform = DAffine2::from_translation((quad.top_left() + quad.top_right()) / 2.);
			self.text(width, COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]);
		}

		if translation.y.abs() > 1e-3 {
			self.dashed_line(quad.top_left(), quad.bottom_left(), None, None, Some(2.), Some(2.), Some(0.5));

View on GitHub (pinned to c507b35645)

Solutions

  1. Treat context loss as recoverable: detect the failure, rebuild the render context, and redraw on the next frame
  2. Swap the expect for a logged if-let so text drawing degrades to a missing label rather than a WASM abort
  3. Ensure the canvas backing the OverlayResource outlives every scheduled overlay render

Example fix

// before
self.render_context.fill_text(text, 0., 0.).expect("Failed to draw the text at the calculated position");

// after
if let Err(e) = self.render_context.fill_text(text, 0., 0.) {
	log::error!("Failed to draw overlay text {text:?}: {e:?}");
}
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(js_err) = self.render_context.fill_text(text, 0., 0.) {
	log::error!("fill_text failed for {text:?}: {js_err:?}");
	// still try to reset the transform so later overlays are unaffected
	let _ = self.render_context.reset_transform();
}

Prevention

When it happens

Trigger: 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.

Common situations: Canvas removed from DOM while overlays are mid-frame; context loss under GPU/memory pressure; rapid tab discard/restore during editing.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/8932d78f9f456da7. Report an issue: GitHub.