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
- Do not transferControlToOffscreen canvases used by this code path; bind to the offscreen context type instead
- Check has_type::<CanvasRenderingContext2d>() before casting and degrade gracefully
- 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
- Never call transferControlToOffscreen on canvases used for 2D blitting
- Test canvas interop in real browsers, not DOM emulations
- Prefer dyn_ref over dyn_into anywhere a host could supply an unexpected context class
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
- Failed to cast context to CanvasRenderingContext2d
- Failed to cast element to HtmlCanvasElement
- Failed to draw arc
- Failed to get canvas context
- Context should be a canvas 2d context
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/c95d4c1a14a6fb75.
Report an issue: GitHub.