{"record":{"id":"a98ec430ae0b64c8","repo":"BabylonJS/Babylon.js","slug":"failed-to-get-2d-context","errorCode":null,"errorMessage":"Failed to get 2D context","messagePattern":"Failed to get 2D context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/loaders/src/SPLAT/sog.pure.ts","lineNumber":114,"sourceCode":"}\r\nconst SH_C0 = 0.28209479177387814;\r\n\r\nasync function LoadWebpImageData(rootUrlOrData: string | Uint8Array, filename: string, engine: AbstractEngine): Promise<IWebPImage> {\r\n    const promise = new Promise<IWebPImage>((resolve, reject) => {\r\n        const image = engine.createCanvasImage();\r\n        if (!image) {\r\n            throw new Error(\"Failed to create ImageBitmap\");\r\n        }\r\n        image.onload = () => {\r\n            try {\r\n                // Draw to canvas\r\n                const canvas = engine.createCanvas(image.width, image.height);\r\n                if (!canvas) {\r\n                    throw new Error(\"Failed to create canvas\");\r\n                }\r\n                const ctx = canvas.getContext(\"2d\");\r\n                if (!ctx) {\r\n                    throw new Error(\"Failed to get 2D context\");\r\n                }\r\n                ctx.drawImage(image, 0, 0);\r\n\r\n                // Extract pixel data (RGBA per pixel)\r\n                const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n                resolve({ bits: new Uint8Array(imageData.data.buffer), width: imageData.width, height: imageData.height });\r\n            } catch (error) {\r\n                // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\r\n                reject(`Error loading image ${image.src} with exception: ${error}`);\r\n            }\r\n        };\r\n        image.onerror = (error) => {\r\n            // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\r\n            reject(`Error loading image ${image.src} with exception: ${error}`);\r\n        };\r\n\r\n        image.crossOrigin = \"anonymous\"; // To avoid CORS issues\r\n        let objectUrl: string | undefined;\r","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/loaders/src/SPLAT/sog.pure.ts#L96-L132","documentation":"To read raw RGBA pixels for SOG splat data, LoadWebpImageData obtains a 2D rendering context from the created canvas via getContext(\"2d\"). If the context is unavailable (null), pixel data cannot be extracted and this error is thrown. Some environments create canvases without 2D context support (e.g. WebGL-only canvases).","triggerScenarios":"canvas.getContext(\"2d\") returning null during image.onload — canvas backend without 2D support, or a canvas previously acquired with a different context type.","commonSituations":"Polyfilled canvas whose getContext only supports 'webgl'; engines reusing a canvas already bound to a WebGL context; restricted environments (WebGL-only headless renderers).","solutions":["Use a canvas implementation that supports 2D contexts (browser canvas, node-canvas, or full OffscreenCanvas support).","Do not pass a canvas already used for WebGL as the 2D extraction target; create a dedicated canvas.","Update the polyfill/engine so createCanvas returns a fresh 2D-capable canvas.","Catch the rejection and fall back to an alternative WebP decoder (e.g. decodeImage + manual RGBA conversion)."],"exampleFix":"// before\nconst sharedCanvas = engine.getRenderingCanvas();\nsharedCanvas.getContext(\"webgl\"); // earlier\n// later getContext(\"2d\") -> null -> error\n// after\nconst extractCanvas = document.createElement(\"canvas\"); // dedicated 2D canvas\nconst ctx = extractCanvas.getContext(\"2d\");","handlingStrategy":"fallback","validationCode":"const probe = document.createElement(\"canvas\").getContext(\"2d\");\nif (!probe) {\n  throw new Error(\"2D canvas context unavailable; cannot extract SOG pixels\");\n}","typeGuard":"function has2DContext(engine: AbstractEngine): boolean {\n  const c = (engine as any).createCanvas?.(1, 1);\n  return !!c && !!c.getContext(\"2d\");\n}","tryCatchPattern":"try {\n  const data = await loadMeansImageAsync(url, engine);\n} catch (e) {\n  if (String(e.message) === \"Failed to get 2D context\") {\n    // fallback: decode with OffscreenCanvas(2d) or a WASM WebP decoder\n    const off = new OffscreenCanvas(w, h);\n    const ctx = off.getContext(\"2d\");\n  } else throw e;\n}","preventionTips":["Never reuse a WebGL-bound canvas for 2D pixel extraction; use a dedicated canvas.","Ensure your canvas polyfill supports the '2d' context type, not just 'webgl'.","Feature-test getContext('2d') in CI to catch headless environment gaps early.","Keep a WASM WebP decoder fallback for WebGL-only renderers."],"tags":["splat","sog","canvas-2d","environment"],"backgroundTag":"canvas-2d-context-unavailable","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}