GraphiteEditor/Graphite · error

Failed to cast context to CanvasRenderingContext2d

Error message

Failed to cast context to CanvasRenderingContext2d

What it means

The final step of CanvasImpl::context casts the value returned by getContext("2d") with dyn_into::<CanvasRenderingContext2d>(). The call succeeded, but the object is not an instance of the standard 2D context class — offscreen 2D contexts and polyfills have a different prototype chain, so the cast is rejected.

Source

Thrown at node-graph/libraries/canvas-utils/src/wasm.rs:187

		// Convert key and value to JsValue
		let js_key = JsValue::from_str(canvas_id.to_string().as_str());
		let js_value = JsValue::from(canvas.clone());

		let canvases = Object::from(canvases.unwrap());

		// Use Reflect API to set property
		Reflect::set(&canvases, &js_key, &js_value).unwrap();

		Self { canvas_id, canvas }
	}
	fn context(&self) -> CanvasRenderingContext2d {
		self.canvas
			.get_context("2d")
			.expect("Failed to get 2D context from canvas")
			.unwrap()
			.dyn_into::<CanvasRenderingContext2d>()
			.expect("Failed to cast context to CanvasRenderingContext2d")
	}
	fn set_resolution(&self, resolution: glam::UVec2) {
		self.canvas.set_width(resolution.x);
		self.canvas.set_height(resolution.y);
	}
}

impl Drop for CanvasImpl {
	fn drop(&mut self) {
		let canvas_id = self.canvas_id;
		let window = window().expect("should have a window in this context");
		let window_obj = Object::from(window);

		let image_canvases_key = JsValue::from_str(CANVASES_OBJECT_KEY);

		if let Ok(canvases) = Reflect::get(&window_obj, &image_canvases_key) {
			let canvases = Object::from(canvases);
			let js_key = JsValue::from_str(canvas_id.to_string().as_str());

View on GitHub (pinned to c507b35645)

Solutions

  1. Do not transferControlToOffscreen canvases used by this code path; bind to the offscreen context type instead
  2. Check has_type::<CanvasRenderingContext2d>() before casting and degrade gracefully
  3. Test canvas code in real browsers rather than DOM emulations

Example fix

// before
.dyn_into::<CanvasRenderingContext2d>()
	.expect("Failed to cast context to CanvasRenderingContext2d")

// after
let Ok(context) = value.dyn_into::<CanvasRenderingContext2d>() else {
	error!("got {:?} instead of a 2D rendering context", value.js_typeof());
	return;
};
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure the value is the standard context class before casting
value.has_type::<CanvasRenderingContext2d>()

Type guard

fn as_2d_context(value: &JsValue) -> Option<CanvasRenderingContext2d> {
	value.dyn_ref::<CanvasRenderingContext2d>().cloned()
}

Prevention

When it happens

Trigger: An OffscreenCanvasRenderingContext2D returned after transferControlToOffscreen; jsdom or polyfill contexts that are not true instances; prototype tampering on the context class.

Common situations: Node/jsdom test suites exercising wasm canvas code; moving raster work into workers; older browsers with non-standard context objects.

Related errors


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