GraphiteEditor/Graphite · error

Failed to draw ellipse

Error message

Failed to draw ellipse

What it means

Calls ellipse_with_anticlockwise, which maps to JS CanvasRenderingContext2D.ellipse(). The browser throws IndexSizeError when radius_x or radius_y is negative, and errors can also occur with non-finite arguments; wasm-bindgen surfaces any JS throw as Err(JsValue), which this .expect escalates into a Rust panic that aborts the overlay render pass.

Source

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

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

		self.render_context.begin_path();
		self.render_context
			.ellipse_with_anticlockwise(
				center.x,
				center.y,
				radius_x,
				radius_y,
				rotation.unwrap_or_default(),
				start_angle.unwrap_or_default(),
				end_angle.unwrap_or(TAU),
				counterclockwise.unwrap_or_default(),
			)
			.expect("Failed to draw ellipse");
		self.render_context.set_stroke_style_str(color_stroke);

		if let Some(fill_color) = color_fill {
			self.render_context.set_fill_style_str(fill_color);
			self.render_context.fill();
		}
		self.render_context.stroke();

		// Reset the dash pattern back to solid
		if dash_width.is_some() {
			self.render_context
				.set_line_dash(&JsValue::from(js_sys::Array::new()))
				.map_err(|error| log::warn!("Error drawing dashed line: {:?}", error))
				.ok();
		}
		if dash_offset.is_some() && dash_offset != Some(0.) {
			self.render_context.set_line_dash_offset(0.);
		}

View on GitHub (pinned to c507b35645)

Solutions

  1. Clamp and validate radii before the call: early-return unless radius_x/radius_y are finite and >= 0.
  2. Trace NaN to its source — add is_finite debug assertions on viewport/document transforms when they are computed, not when they are drawn.
  3. Replace .expect with a logged .ok()/if-let so one bad ellipse cannot kill the whole overlay frame.
  4. Log the ellipse arguments when the call fails so the offending geometry is identifiable in reports.

Example fix

// before
self.render_context
	.ellipse_with_anticlockwise(center.x, center.y, radius_x, radius_y, rotation, start_angle, end_angle, ccw)
	.expect("Failed to draw ellipse");

// after
if radius_x.is_finite() && radius_y.is_finite() && radius_x >= 0. && radius_y >= 0. {
	if let Err(err) = self.render_context.ellipse_with_anticlockwise(center.x, center.y, radius_x, radius_y, rotation, start_angle, end_angle, ccw) {
		log::warn!("Failed to draw ellipse: {:?}", err);
	}
}
Defensive patterns

Strategy: validation

Validate before calling

fn ellipse_args_safe(center: DVec2, radius_x: f64, radius_y: f64) -> bool {
	center.x.is_finite()
		&& center.y.is_finite()
		&& radius_x.is_finite()
		&& radius_y.is_finite()
		&& radius_x >= 0.
		&& radius_y >= 0.
}

Type guard

fn is_drawable_radius(radius: f64) -> bool {
	radius.is_finite() && radius >= 0.
}

Try / catch

if let Err(err) = self
	.render_context
	.ellipse_with_anticlockwise(center.x, center.y, radius_x, radius_y, rot, start, end, ccw)
{
	log::warn!("overlay ellipse failed: {:?}", err);
}

Prevention

When it happens

Trigger: Drawing an ellipse overlay whose radii were computed from degenerate geometry — mirrored or inverted bounds where the width/height difference goes negative, or NaN leaking from a corrupted document/viewport transform — so radius_x/radius_y arrive negative or non-finite.

Common situations: Flipped/mirrored layers producing negative values in bounding-box math; division by zero zoom yielding NaN upstream; fuzzed or malformed documents feeding non-finite geometry into overlay drawing.

Related errors


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