GraphiteEditor/Graphite · error

Failed to transform circle

Error message

Failed to transform circle

What it means

Applies a caller-supplied DAffine2 to the canvas via ctx.transform(a, b, c, d, e, f). The JS transform() throws when the matrix is non-invertible or contains non-finite values (NaN/Inf). The matrix comes from the transform: Option<DAffine2> parameter of dashed_circle; a singular (zero-determinant) or NaN-corrupted affine makes the call throw and the .expect panic, aborting the overlay frame.

Source

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

	pub fn dashed_circle(
		&mut self,
		position: DVec2,
		radius: f64,
		color_fill: Option<&str>,
		color_stroke: Option<&str>,
		dash_width: Option<f64>,
		dash_gap_width: Option<f64>,
		dash_offset: Option<f64>,
		transform: Option<DAffine2>,
	) {
		let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
		let position = self.snap_to_physical_pixel(position);

		self.start_dpi_aware_transform();

		if let Some(transform) = transform {
			let [a, b, c, d, e, f] = transform.to_cols_array();
			self.render_context.transform(a, b, c, d, e, f).expect("Failed to transform circle");
		}

		if let Some(dash_width) = dash_width {
			let dash_gap_width = dash_gap_width.unwrap_or(1.);
			let array = js_sys::Array::new();
			array.push(&JsValue::from(dash_width));
			array.push(&JsValue::from(dash_gap_width));

			if let Some(dash_offset) = dash_offset {
				if dash_offset != 0. {
					self.render_context.set_line_dash_offset(dash_offset);
				}
			}

			self.render_context
				.set_line_dash(&JsValue::from(array))
				.map_err(|error| log::warn!("Error drawing dashed line: {:?}", error))
				.ok();

View on GitHub (pinned to c507b35645)

Solutions

  1. Validate the affine before applying: all six entries finite and the 2x2 determinant non-zero; fall back to skipping the transform.
  2. Fix upstream zero-scale computation — guard divisions by viewport size and zoom.
  3. Swap .expect for a logged if-let Err so a bad matrix cannot crash the frame.

Example fix

// before
self.render_context.transform(a, b, c, d, e, f).expect("Failed to transform circle");

// after
let invertible = [a, b, c, d, e, f].iter().all(|v| v.is_finite()) && a * d - b * c != 0.;
if invertible {
	if let Err(err) = self.render_context.transform(a, b, c, d, e, f) {
		log::warn!("Failed to apply circle transform: {:?}", err);
	}
}
Defensive patterns

Strategy: validation

Validate before calling

fn affine_is_drawable(transform: DAffine2) -> bool {
	let [a, b, c, d, e, f] = transform.to_cols_array();
	[a, b, c, d, e, f].iter().all(|v| v.is_finite()) && a * d - b * c != 0.
}

Type guard

fn is_invertible_2d(transform: DAffine2) -> bool {
	let det = transform.matrix2.determinant();
	det.is_finite() && det != 0.
}

Try / catch

if let Err(err) = self.render_context.transform(a, b, c, d, e, f) {
	log::warn!("failed to apply canvas transform: {:?}", err);
}

Prevention

When it happens

Trigger: Drawing a dashed circle overlay with a transform whose determinant is zero (zero-scaled view) or whose coefficients are NaN — typically computed from a zero-size viewport or a division by zero earlier in the transform stack.

Common situations: Zoom or resize edge cases producing 0/NaN scale; gizmo overlays receiving document transforms that became singular after extreme scaling values.

Related errors


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