GraphiteEditor/Graphite · error
Failed to get canvas context
Error message
Failed to get canvas context
What it means
fill_path_pattern creates a fresh 4x4 OffscreenCanvas per call and does get_context("2d").ok().flatten().expect("Failed to get canvas context"). get_context returns Err if the call throws and None if a 2D context cannot be created (context limits, memory pressure, or the runtime not fully implementing OffscreenCanvas 2D). This expect panics in WASM whenever context creation fails, which is most likely on browsers with partial OffscreenCanvas support or under resource exhaustion because a new canvas is allocated on every fill-tool hover.
Source
Thrown at editor/src/messages/portfolio/document/overlays/utility_types_web.rs:1026
pub fn fill_path(&mut self, subpaths: impl Iterator<Item = impl Borrow<Subpath<PointId>>>, transform: DAffine2, color: &str) {
self.push_path(subpaths, transform);
self.render_context.set_fill_style_str(color);
self.render_context.fill();
}
/// Fills the area inside the path with a pattern. Assumes `color` is an sRGB hex string.
/// Used by the fill tool to show the area to be filled.
pub fn fill_path_pattern(&mut self, subpaths: impl Iterator<Item = impl Borrow<Subpath<PointId>>>, transform: DAffine2, color: &str) {
const PATTERN_WIDTH: usize = 4;
const PATTERN_HEIGHT: usize = 4;
let pattern_canvas = OffscreenCanvas::new(PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap();
let pattern_context: OffscreenCanvasRenderingContext2d = pattern_canvas
.get_context("2d")
.ok()
.flatten()
.expect("Failed to get canvas context")
.dyn_into()
.expect("Context should be a canvas 2d context");
// 4x4 pixels, 4 components (RGBA) per pixel
let mut data = [0_u8; 4 * PATTERN_WIDTH * PATTERN_HEIGHT];
let rgba = hex_to_rgba_u8(color);
// ┌▄▄┬──┬──┬──┐
// ├▀▀┼──┼──┼──┤
// ├──┼──┼▄▄┼──┤
// ├──┼──┼▀▀┼──┤
// └──┴──┴──┴──┘
let pixels = [(0, 0), (2, 2)];
for &(x, y) in &pixels {
let index = (x + y * PATTERN_WIDTH) * 4;
data[index..index + 4].copy_from_slice(&rgba);
}View on GitHub (pinned to c507b35645)
Solutions
- Cache one shared 4x4 pattern OffscreenCanvas (and only rewrite its pixels when the color changes) instead of allocating per call
- Feature-detect OffscreenCanvas 2D once at startup and fall back to a document.createElement('canvas') path when unavailable
- Handle the None case with a log and a solid-color fill instead of expect, so the fill preview degrades instead of aborting
Example fix
// before
let pattern_context: OffscreenCanvasRenderingContext2d = pattern_canvas
.get_context("2d")
.ok()
.flatten()
.expect("Failed to get canvas context")
.dyn_into()
.expect("Context should be a canvas 2d context");
// after
let Some(ctx) = pattern_canvas.get_context("2d").ok().flatten() else {
log::error!("Failed to get 2D context for fill pattern");
return;
};
let pattern_context: OffscreenCanvasRenderingContext2d = ctx.dyn_into().expect("Context should be a canvas 2d context"); Defensive patterns
Strategy: validation
Validate before calling
// feature-detect once, and cache the pattern canvas instead of allocating per call
use wasm_bindgen::JsValue;
if !js_sys::Reflect::get(&wasm_bindgen::global(), &"OffscreenCanvas".into()).map(|v| !v.is_undefined()).unwrap_or(false) {
// fall back to solid fill; do not call fill_path_pattern
} Try / catch
match pattern_canvas.get_context("2d") {
Ok(Some(ctx)) => { /* use ctx */ }
Ok(None) => log::error!("2D context unavailable for fill pattern"),
Err(e) => log::error!("get_context threw: {e:?}"),
} Prevention
- Cache a single small OffscreenCanvas for patterns rather than creating one per fill-tool hover
- Feature-detect OffscreenCanvas 2D support at startup and disable/fall back the patterned preview
- Free pattern contexts (set to None) when the fill tool is deactivated to avoid context exhaustion
When it happens
Trigger: Invoking the fill tool overlay (fill_path_pattern) on a browser where OffscreenCanvas exists but get_context("2d") returns null (Safari < 16.4-era WebKit, some WebViews), or after allocating so many short-lived OffscreenCanvases that the browser refuses another context.
Common situations: Older Safari/iOS WebViews with incomplete OffscreenCanvas; headless test environments; memory-constrained devices where per-call canvas creation exhausts the context budget.
Related errors
- Failed to draw arc
- Context should be a canvas 2d context
- Failed to measure the text dimensions
- Failed to rotate the render context to the specified angle
- Failed to draw the text at the calculated position
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/7d72028798633e79.
Report an issue: GitHub.