{"record":{"id":"3f6a0bed66a2c686","repo":"BabylonJS/Babylon.js","slug":"unable-to-get-2d-context","errorCode":null,"errorMessage":"Unable to get 2d context","messagePattern":"Unable to get 2d context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Engines/Extensions/engine.videoTexture.pure.ts","lineNumber":52,"sourceCode":"                this._gl.getError();\r\n\r\n                this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalFormat, glformat, this._gl.UNSIGNED_BYTE, video);\r\n\r\n                if (this._gl.getError() !== 0) {\r\n                    this._videoTextureSupported = false;\r\n                } else {\r\n                    this._videoTextureSupported = true;\r\n                }\r\n            }\r\n\r\n            // Copy video through the current working canvas if video texture is not supported\r\n            if (!this._videoTextureSupported) {\r\n                if (!texture._workingCanvas) {\r\n                    texture._workingCanvas = this.createCanvas(texture.width, texture.height);\r\n                    const context = texture._workingCanvas.getContext(\"2d\");\r\n\r\n                    if (!context) {\r\n                        throw new Error(\"Unable to get 2d context\");\r\n                    }\r\n\r\n                    texture._workingContext = context;\r\n                    texture._workingCanvas.width = texture.width;\r\n                    texture._workingCanvas.height = texture.height;\r\n                }\r\n\r\n                texture._workingContext!.clearRect(0, 0, texture.width, texture.height);\r\n                texture._workingContext!.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, texture.width, texture.height);\r\n\r\n                this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalFormat, glformat, this._gl.UNSIGNED_BYTE, texture._workingCanvas as TexImageSource);\r\n            } else {\r\n                this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalFormat, glformat, this._gl.UNSIGNED_BYTE, video);\r\n            }\r\n\r\n            if (texture.generateMipMaps) {\r\n                this._gl.generateMipmap(this._gl.TEXTURE_2D);\r\n            }\r","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Engines/Extensions/engine.videoTexture.pure.ts#L34-L70","documentation":"When copying a video frame into a texture, the engine creates an offscreen canvas and requests a '2d' rendering context from it. If canvas.getContext('2d') returns null, this error is thrown. getContext returns null only when a context of a different type was already requested on that canvas or the canvas is unusable.","triggerScenarios":"Calling video texture creation (e.g. engine.createVideoTexture, or _createVideoTexture fallback path used by WebXR layers) where texture._workingCanvas already had a non-2d context (e.g. 'webgl') obtained earlier, so getContext('2d') returns null.","commonSituations":"Reusing the same HTMLCanvasElement across both a WebGL texture and a 2d drawing surface; WebXR passthrough/layers fallback path creating a canvas whose context type conflicts; browser policies or extensions blocking canvas 2d contexts.","solutions":["Ensure the working canvas used for video texture copies is dedicated and never previously requested as a 'webgl' (or other) context — create a fresh canvas per texture","If reusing a canvas, check canvas.getContext('2d') yourself before handing it to the engine and use a separate canvas if null","Update to a recent Babylon.js version; older videoTexture fallback paths had canvas-reuse bugs","Rule out browser settings/extensions that block canvas contexts (privacy modes, canvas blockers)"],"exampleFix":"// before\nconst shared = document.createElement('canvas');\nshared.getContext('webgl');\nengine.createVideoTexture(url, { canvas: shared });\n// after\nconst dedicated = document.createElement('canvas'); // no prior context request\nengine.createVideoTexture(url, null, { ...options });","handlingStrategy":"validation","validationCode":"function hasUsable2DCanvas(engine: any): boolean {\n  const probe = engine.createCanvas(1, 1);\n  const ctx = probe.getContext('2d');\n  return !!ctx;\n}","typeGuard":"function is2DContext(ctx: CanvasRenderingContext2D | null): ctx is CanvasRenderingContext2D {\n  return ctx !== null;\n}","tryCatchPattern":null,"preventionTips":["Never request a 'webgl' context on a canvas you intend to hand to video texture copying","Use a dedicated, freshly created canvas per video texture","Test video texture creation in all target browsers early (policies differ)","Keep Babylon.js updated — video texture canvas fallbacks have been fixed over time"],"tags":["webgl","video","canvas","texture"],"backgroundTag":"canvas-context-null","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}