GraphiteEditor/Graphite · error

Failed to draw the circle

Error message

Failed to draw the circle

What it means

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.

Source

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

			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();
		}

		self.render_context.begin_path();
		self.render_context.arc(position.x, position.y, radius, 0., TAU).expect("Failed to draw the circle");
		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 radius at dashed_circle entry: skip drawing unless radius.is_finite() && radius >= 0.
  2. Find the producer of the negative/NaN radius (zoom scale, bounds subtraction) and fix it at the source.
  3. Degrade .expect to a logged if-let Err so one bad circle skips instead of crashing the overlay pass.

Example fix

// before
self.render_context.arc(position.x, position.y, radius, 0., TAU).expect("Failed to draw the circle");

// after
if radius.is_finite() && radius >= 0. {
	if let Err(err) = self.render_context.arc(position.x, position.y, radius, 0., TAU) {
		log::warn!("Failed to draw the circle: {:?}", err);
	}
}
Defensive patterns

Strategy: validation

Validate before calling

fn circle_drawable(position: DVec2, radius: f64) -> bool {
	position.x.is_finite() && position.y.is_finite() && radius.is_finite() && radius >= 0.
}

Type guard

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

Try / catch

if let Err(err) = self.render_context.arc(position.x, position.y, radius, 0., TAU) {
	log::warn!("overlay circle failed: {:?}", err);
}

Prevention

When it happens

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

Common situations: 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.

Related errors


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