AvaloniaUI/Avalonia · error · Error

HTMLCanvasElement.getContext returned null.

Error message

HTMLCanvasElement.getContext returned null.

What it means

Thrown by the WebGlRenderTarget constructor when canvas.getContext('webgl'/'webgl2') returns null. The request uses failIfMajorPerformanceCaveat:true, so a context backed only by a software rasterizer is deliberately rejected, and a genuine null means the browser declined to create a WebGL context.

Source

Thrown at src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/webGlRenderTarget.ts:56

                depth: true,
                stencil: true,
                antialias: false,
                premultipliedAlpha: true,
                preserveDrawingBuffer: false,
                // only supported on older browsers, which is perfect as we want to fallback to 2d there.
                failIfMajorPerformanceCaveat: true,
                // attrs used by Emscripten:
                majorVersion: mode === BrowserRenderingMode.WebGL1 ? 1 : 2,
                minorVersion: 0,
                enableExtensionsByDefault: 1,
                explicitSwapControl: 0
            };

        const context = (mode === BrowserRenderingMode.WebGL1
            ? canvas.getContext("webgl", attrs)
            : canvas.getContext("webgl2", attrs)) as WebGLRenderingContext;
        if (!context) {
            throw new Error("HTMLCanvasElement.getContext returned null.");
        }

        const handle = WebGlRenderTarget._gl.registerContext(context, attrs);
        (context as any).gl_handle = handle;
        super(canvas, "webgl");

        this.contextHandle = handle;
        this.fboId = context.getParameter(context.FRAMEBUFFER_BINDING)?.id ?? 0;
        this.stencil = context.getParameter(context.STENCIL_BITS);
        this.sample = context.getParameter(context.SAMPLES);
        this.depth = context.getParameter(context.DEPTH_BITS);
        this.attrs = attrs;
    }

    public static getCurrentContext(): number {
        return WebGlRenderTarget._gl?.currentContext?.handle ?? 0;
    }

View on GitHub (pinned to 11c5427268)

Solutions

  1. List WebGL1 before WebGL2 in preferredModes so browsers without WebGL2 can fall back.
  2. Keep Software2D as the last preferred mode so createRenderTarget can recover.
  3. Ensure the canvas given to WebGL has not already acquired a 2D context and was not transferred offscreen.
  4. For headless tests, launch the browser with software WebGL flags or supply a WebGL polyfill.

Example fix

// before
preferredModes = [BrowserRenderingMode.WebGL2, BrowserRenderingMode.WebGL1]
// -> WebGL2 null on an older device throws and aborts

// after
preferredModes = [BrowserRenderingMode.WebGL2, BrowserRenderingMode.WebGL1, BrowserRenderingMode.Software2D]
Defensive patterns

Strategy: fallback

Validate before calling

function supportsMode(mode: BrowserRenderingMode, canvas: HTMLCanvasElement | OffscreenCanvas): boolean {
  const t = mode === BrowserRenderingMode.WebGL1 ? 'webgl' : 'webgl2';
  return canvas.getContext(t) != null; // note: probe only; do not consume in production
}

Type guard

function hasWebGL2(canvas: HTMLCanvasElement | OffscreenCanvas): boolean {
  return canvas.getContext('webgl2') != null;
}

Try / catch

try { return new WebGlRenderTarget(canvas, mode); }
catch (e) {
  if (e instanceof Error && /getContext/.test(e.message)) { /* try next preferred mode */ }
  throw e;
}

Prevention

When it happens

Trigger: Requesting a 'webgl2' context on a browser/device that only supports WebGL1; a canvas already bound to a 2D context; the device uses a software WebGL implementation (blocked by failIfMajorPerformanceCaveat); WebGL disabled in the browser; the canvas was consumed by transferControlToOffscreen on the main thread.

Common situations: Older/mobile browsers without WebGL2; headless CI browsers with no GPU; user disabled hardware acceleration; failIfMajorPerformanceCaveat rejecting a SwiftShader fallback; reusing a canvas that already got a 2D context for software rendering.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/ec14e0fbbe61d3a0. Report an issue: GitHub.