AvaloniaUI/Avalonia · critical · Error
Module.GL object wasn't initialized, WebGL can't be used.
Error message
Module.GL object wasn't initialized, WebGL can't be used.
What it means
Thrown by the WebGlRenderTarget constructor when getGL() returns a falsy value. getGL() looks for the Emscripten Module.GL object (or global AvaloniaGL/SkiaSharpGL shims) that Skia uses to wrap a WebGL context for Emscripten interop. A null result means none of those interop hooks are present on the global object.
Source
Thrown at src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/webGlRenderTarget.ts:32
const self = globalThis as any;
const module = self.Module ?? self.getDotnetRuntime(0)?.Module;
return (module?.GL ?? self.AvaloniaGL ?? self.SkiaSharpGL) as EmscriptenGL;
}
export class WebGlRenderTarget extends WebRenderTarget {
public contextHandle?: number;
public attrs: WebGLContextAttributes;
public fboId?: number;
public stencil?: number;
public sample?: number;
public depth?: number;
private static _gl: EmscriptenGL | null = null;
constructor(public canvas: HTMLCanvasElement | OffscreenCanvas, mode: BrowserRenderingMode) {
// Skia only understands WebGL context wrapped in Emscripten.
if (WebGlRenderTarget._gl == null) { WebGlRenderTarget._gl = getGL(); }
if (!WebGlRenderTarget._gl) {
throw new Error("Module.GL object wasn't initialized, WebGL can't be used.");
}
const attrs: WebGLContextAttributes | any =
{
alpha: true,
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
};View on GitHub (pinned to 11c5427268)
Solutions
- Wait for the Avalonia WASM runtime 'ready'/'started' signal before creating any WebGL render target.
- Verify the GL interop script (the one setting globalThis.AvaloniaGL or Module.GL) is bundled and executed without errors.
- Supply a fallback so createRenderTarget falls through to Software2D when WebGL setup throws.
- Check the browser console for earlier script-load errors that prevented Module.GL assignment.
Example fix
// before
const rt = new WebGlRenderTarget(canvas, BrowserRenderingMode.WebGL2); // Module.GL not ready
// after
await runtimeReady;
if (!globalThis.Module?.GL && !globalThis.AvaloniaGL) { /* fall back to software */ }
const rt = new WebGlRenderTarget(canvas, BrowserRenderingMode.WebGL2); Defensive patterns
Strategy: validation
Validate before calling
const gl = globalThis.Module?.GL ?? globalThis.AvaloniaGL ?? globalThis.SkiaSharpGL;
if (!gl) { /* not ready: defer or fall back to software */ } Type guard
function hasEmscriptenGL(): boolean {
const self = globalThis as any;
const m = self.Module ?? self.getDotnetRuntime?.(0)?.Module;
return !!(m?.GL ?? self.AvaloniaGL ?? self.SkiaSharpGL);
} Try / catch
try { return new WebGlRenderTarget(canvas, mode); }
catch (e) {
if (e instanceof Error && e.message.includes('Module.GL')) { /* fall back to Software2D */ return new SoftwareRenderTarget(canvas); }
throw e;
} Prevention
- Wait for the Avalonia WASM runtime ready event before creating WebGL targets.
- Confirm the GL interop script loaded (check console).
- Always keep Software2D as a last fallback mode.
When it happens
Trigger: Constructing new WebGlRenderTarget(canvas, mode) before the Avalonia/SkiaSharp WASM module finished loading and set Module.GL on globalThis; the interop JS that assigns AvaloniaGL/SkiaGL failed to load (script error, wrong build artifact); running in an environment where Module is absent.
Common situations: Misordered script loading so rendering starts before the WASM bootstrapper defines Module.GL; bundler tree-shook or renamed the global assignment; dev server serving a stale build without the GL interop; SSR/prerender pass hitting rendering code with no Module.
Related errors
- Unable to access emscripten PThread api
- Unable to access .NET memory
- HTMLCanvasElement.getContext returned null.
- Unable get pthread with id ${pthreadId}
- Unable get Worker for pthread ${pthreadId}
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/71ff5b3854208f74.
Report an issue: GitHub.