fix(viewer): guard 3D viewer against null WebGL context (Sentry MONOREPO-EDITOR-59)#455
fix(viewer): guard 3D viewer against null WebGL context (Sentry MONOREPO-EDITOR-59)#455anton-pascal wants to merge 1 commit into
Conversation
…er (MONOREPO-EDITOR-59) Guard the /viewer/:id route against the null-GL-context crash: TypeError: Cannot read properties of null (reading 'getSupportedExtensions') (Sentry MONOREPO-EDITOR-59, 5282 events / 0 users = headless bots & GPU-blocklisted browsers). canMountGpuViewer() previously mounted whenever 'gpu' in navigator was truthy. That flag does not guarantee WebGPU can produce a device: on headless/blocklisted browsers the adapter request fails and three.js falls back to a WebGL backend. With no obtainable WebGL context, three calls getSupportedExtensions() on the null context inside renderer.init() and throws. Since the WebGPURenderer fallback path always needs WebGL, an obtainable WebGL context is the real precondition for mounting. Require it unconditionally so bots hit the existing UnsupportedGpuViewerFallback instead of crashing. Real WebGPU-capable browsers always expose WebGL, so no capable device is newly excluded.
|
Nightly Sentry triage (2026-07-11) — EDITOR-59 recurred with a new latest event (issue 7415398488) but this time from transaction Heads up that the guard in this PR touches |
|
Nightly Sentry triage 2026-07-13: MONOREPO-EDITOR-59 ( |
|
Sentry MONOREPO-EDITOR-FM ( |
Sentry MONOREPO-EDITOR-59
TypeError: Cannot read properties of null (reading 'getSupportedExtensions')— 5282 events / 0 users.The 0-users signature is the tell: this is headless bot / crawler traffic (plus GPU-blocklisted or hardware-acceleration-disabled browsers) hitting the public
/viewer/:idroute.Root cause
Stack: three.js
three.webgpu.js→Backend/Rendererinit→ WebGPU is unavailable so three.js transparently falls back to a WebGL backend →canvas.getContext('webgl2' | 'webgl')returnsnull→ three callsgl.getSupportedExtensions()on the null context and throws.The viewer already has a capability gate (
canMountGpuViewer, added in #403) plus anUnsupportedGpuViewerFallback. But the gate mounted the canvas whenever'gpu' in navigatorwas truthy:That
navigator.gpuflag being present does not guarantee WebGPU can produce a device. On headless/blocklisted browsers the adapter request fails, three falls back to WebGL, and if no real WebGL context is obtainable either,renderer.init()throws on the null context — the crash above. So the "optimistic" branch let exactly the crashing population through.The fix
Require an actually obtainable WebGL context before mounting, unconditionally:
Rationale: the
WebGPURendererfallback path always needs WebGL, so a creatable WebGL context is the true, verifiable precondition for mounting. This converts the flaky "gpu-in-navigator" optimism into a hard gate:UnsupportedGpuViewerFallbackUI instead of crashing.Minimal, low-risk: one predicate changed, reusing the existing
canCreateWebGLContext()helper and the existing fallback UI. No renderer/init refactor.Scope
packages/viewer/src/components/viewer/index.tsx(the/viewerroute renderer gate).Do not merge without review.
Note
Low Risk
Single predicate change in the viewer capability gate with existing fallback UI; no auth or data paths touched.
Overview
Tightens the public viewer mount gate so environments that cannot create a real WebGL context never mount the WebGPU canvas.
canMountGpuViewerno longer treats'gpu' in navigatoras enough to proceed. It now always requirescanCreateWebGLContext()to pass, because three.js WebGPU init can fall back to WebGL and then crash on a null GL context when neither path works (headless crawlers on/viewer/:id). Those clients should hit the existing UnsupportedGpuViewerFallback instead of throwing duringrenderer.init().Inline comments document the Sentry issue and rationale; behavior for normal browsers with WebGPU + WebGL is unchanged.
Reviewed by Cursor Bugbot for commit c80734d. Bugbot is set up for automated code reviews on this repo. Configure here.