{"record":{"id":"71ff5b3854208f74","repo":"AvaloniaUI/Avalonia","slug":"module-gl-object-wasn-t-initialized-webgl-can-t-b","errorCode":null,"errorMessage":"Module.GL object wasn't initialized, WebGL can't be used.","messagePattern":"Module\\.GL object wasn't initialized, WebGL can't be used\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/webGlRenderTarget.ts","lineNumber":32,"sourceCode":"    const self = globalThis as any;\n    const module = self.Module ?? self.getDotnetRuntime(0)?.Module;\n    return (module?.GL ?? self.AvaloniaGL ?? self.SkiaSharpGL) as EmscriptenGL;\n}\n\nexport class WebGlRenderTarget extends WebRenderTarget {\n    public contextHandle?: number;\n    public attrs: WebGLContextAttributes;\n    public fboId?: number;\n    public stencil?: number;\n    public sample?: number;\n    public depth?: number;\n    private static _gl: EmscriptenGL | null = null;\n\n    constructor(public canvas: HTMLCanvasElement | OffscreenCanvas, mode: BrowserRenderingMode) {\n        // Skia only understands WebGL context wrapped in Emscripten.\n        if (WebGlRenderTarget._gl == null) { WebGlRenderTarget._gl = getGL(); }\n        if (!WebGlRenderTarget._gl) {\n            throw new Error(\"Module.GL object wasn't initialized, WebGL can't be used.\");\n        }\n\n        const attrs: WebGLContextAttributes | any =\n            {\n                alpha: true,\n                depth: true,\n                stencil: true,\n                antialias: false,\n                premultipliedAlpha: true,\n                preserveDrawingBuffer: false,\n                // only supported on older browsers, which is perfect as we want to fallback to 2d there.\n                failIfMajorPerformanceCaveat: true,\n                // attrs used by Emscripten:\n                majorVersion: mode === BrowserRenderingMode.WebGL1 ? 1 : 2,\n                minorVersion: 0,\n                enableExtensionsByDefault: 1,\n                explicitSwapControl: 0\n            };","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/webGlRenderTarget.ts#L14-L50","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst rt = new WebGlRenderTarget(canvas, BrowserRenderingMode.WebGL2); // Module.GL not ready\n\n// after\nawait runtimeReady;\nif (!globalThis.Module?.GL && !globalThis.AvaloniaGL) { /* fall back to software */ }\nconst rt = new WebGlRenderTarget(canvas, BrowserRenderingMode.WebGL2);","handlingStrategy":"validation","validationCode":"const gl = globalThis.Module?.GL ?? globalThis.AvaloniaGL ?? globalThis.SkiaSharpGL;\nif (!gl) { /* not ready: defer or fall back to software */ }","typeGuard":"function hasEmscriptenGL(): boolean {\n  const self = globalThis as any;\n  const m = self.Module ?? self.getDotnetRuntime?.(0)?.Module;\n  return !!(m?.GL ?? self.AvaloniaGL ?? self.SkiaSharpGL);\n}","tryCatchPattern":"try { return new WebGlRenderTarget(canvas, mode); }\ncatch (e) {\n  if (e instanceof Error && e.message.includes('Module.GL')) { /* fall back to Software2D */ return new SoftwareRenderTarget(canvas); }\n  throw e;\n}","preventionTips":["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."],"tags":["browser","rendering","webgl","wasm","emscripten","typescript"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}