fix(deckgl): prevent crash on Intel integrated GPUs when satellite imagery layer fails#2696
Conversation
…agery layer fails - Update deck.gl 9.2.6 → 9.2.11 (latest patch with improved Intel GPU workarounds) - Extend onError handler to catch satellite-imagery-layer shader compilation failures - Skip satellite imagery layer gracefully when WebGL shader compilation fails (prevents app crash) - Follows same graceful-degradation pattern used for apt-groups-layer errors - Add showLayerWarning when satellite layer fails so users understand why imagery disappeared Fixes koala73#2518
|
Someone is attempting to deploy a commit to the World Monitor Team on Vercel. A member of the Team first needs to authorize it. |
Greptile SummaryThis PR attempts to prevent desktop app crashes on Intel integrated GPUs by (1) upgrading deck.gl from 9.2.6 → 9.2.11 for improved Intel GPU shader workarounds, and (2) extending the existing The approach is sound in principle, but there is a critical defect in the implementation:
Confidence Score: 1/5Not safe to merge: the crash-recovery code itself contains a scoping error that will throw a ReferenceError in the exact failure scenario it targets. The core logic (flag + gate in buildLayers) is correct and follows the established pattern, and the deck.gl version bump is straightforward. However, the WARN_THRESHOLD reference at line 839 is a variable that does not exist in that scope — this is a P0 bug that would cause a ReferenceError at the moment the Intel GPU error fires, negating the entire crash-fix. The misleading showLayerWarning() call is a P1 UX regression on top of that. src/components/DeckGLMap.ts lines 837-840 (onError satellite-imagery-layer branch) Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[deck.gl renders frame] --> B{onError fires?}
B -- No --> C[Frame rendered OK]
B -- Yes --> D{error.message includes apt-groups-layer?}
D -- Yes --> E[aptGroupsLayerFailed = true]
D -- No --> F{error.message includes satellite-imagery-layer?}
F -- Yes --> G[satelliteImageryLayerFailed = true]
G --> H[showLayerWarning WARN_THRESHOLD - out of scope - ReferenceError]
F -- No --> I[error logged, ignored]
E --> J[Next buildLayers call]
H --> J
J --> K{satelliteImageryLayerFailed?}
K -- true --> L[Skip createImageryFootprintLayer]
K -- false --> M[Include satellite-imagery-layer]
L --> N[Layer stack returned]
M --> N
Reviews (1): Last reviewed commit: "fix(deckgl): prevent crash on Intel inte..." | Re-trigger Greptile |
| } | ||
| if (error.message.includes('satellite-imagery-layer')) { | ||
| this.satelliteImageryLayerFailed = true; | ||
| showLayerWarning(WARN_THRESHOLD); |
There was a problem hiding this comment.
WARN_THRESHOLD is not in scope — likely a ReferenceError
WARN_THRESHOLD is only defined as a local const inside enforceLayerLimit() at line 5443. It is not a module-level or class-level constant and is therefore completely out of scope inside the onError callback here.
This should cause a TypeScript compilation error (Cannot find name 'WARN_THRESHOLD'). If the build somehow succeeds, this will throw a ReferenceError at runtime whenever the satellite imagery layer fails on an Intel GPU — the exact crash scenario this PR is meant to fix.
The fix should use a numeric literal directly (matching the existing WARN_THRESHOLD = 13 value), or extract WARN_THRESHOLD to a module-level constant shared between enforceLayerLimit() and this handler:
| showLayerWarning(WARN_THRESHOLD); | |
| showLayerWarning(13); |
There was a problem hiding this comment.
Fixed. has been replaced with a GPU-specific followed by . The local const (value 13) is no longer referenced in the callback, eliminating the ReferenceError. The layer stack is now rebuilt immediately after the satellite imagery layer fails.
| if (error.message.includes('satellite-imagery-layer')) { | ||
| this.satelliteImageryLayerFailed = true; | ||
| showLayerWarning(WARN_THRESHOLD); | ||
| } |
There was a problem hiding this comment.
showLayerWarning() shows the wrong message for a GPU shader failure
showLayerWarning(threshold) was built to tell users "You have more than {threshold} layers active, which may degrade performance" (see t('components.deckgl.layerWarningBody', { threshold }) in src/utils/layer-warning.ts). Calling it here for a GPU shader compilation failure will display a deeply misleading message — the user will believe they have too many layers active, when the real cause is an Intel GPU driver incompatibility.
The apt-groups-layer handler deliberately does not call showLayerWarning() (it only sets the flag), so this is also inconsistent with the existing pattern.
A dedicated warning — even a simple console.warn plus a toast/notification — that explains satellite imagery was disabled due to a GPU compatibility issue would be far more helpful to the user.
| if (error.message.includes('satellite-imagery-layer')) { | |
| this.satelliteImageryLayerFailed = true; | |
| showLayerWarning(WARN_THRESHOLD); | |
| } | |
| if (error.message.includes('satellite-imagery-layer')) { | |
| this.satelliteImageryLayerFailed = true; | |
| // TODO: show a GPU-specific warning to the user here | |
| } |
There was a problem hiding this comment.
Fixed. Removed the misleading showLayerWarning() call. Replaced with a descriptive console.warn targeting the Intel GPU driver incompatibility scenario. The onError callback now logs a clear GPU-specific message instead of incorrectly telling users they have too many layers active.
| if (error.message.includes('satellite-imagery-layer')) { | ||
| this.satelliteImageryLayerFailed = true; | ||
| showLayerWarning(WARN_THRESHOLD); | ||
| } |
There was a problem hiding this comment.
Layer not immediately removed after failure
After setting satelliteImageryLayerFailed = true, no explicit rebuild of the layer stack is triggered. The failed layer remains in deck.gl's render list until the next natural buildLayers() call (e.g., on moveend or zoomend). For the apt-groups-layer this is acceptable since it's a static dataset, but satellite imagery is actively fetched on every viewport change — users may see the broken layer linger.
Consider adding a debouncedRebuildLayers() call to flush the failed layer immediately:
| if (error.message.includes('satellite-imagery-layer')) { | |
| this.satelliteImageryLayerFailed = true; | |
| showLayerWarning(WARN_THRESHOLD); | |
| } | |
| if (error.message.includes('satellite-imagery-layer')) { | |
| this.satelliteImageryLayerFailed = true; | |
| showLayerWarning(13); | |
| this.debouncedRebuildLayers(); | |
| } |
There was a problem hiding this comment.
Fixed. Added debouncedRebuildLayers() call immediately after setting satelliteImageryLayerFailed = true. The failed satellite imagery layer is now removed from deck.gl's render list on the very next frame, rather than waiting for the next moveend/zoomend event. Combined with the GPU-specific console.warn (addressing P1), this gives users immediate feedback and correct layer state.
…la73#2696 P0: Replace out-of-scope WARN_THRESHOLD with debouncedRebuildLayers() WARN_THRESHOLD was a local const inside enforceLayerLimit(), not accessible in the onError callback — would cause ReferenceError at runtime on Intel GPU failures. P1: Replace misleading showLayerWarning() with GPU-specific console.warn showLayerWarning() tells users they have too many layers active, which is deeply misleading for a GPU shader compilation failure. Now logs a descriptive GPU incompatibility message instead. P2: Trigger immediate layer stack rebuild after satellite layer failure Added debouncedRebuildLayers() call so the failed layer is removed from deck.gl's render list immediately rather than waiting for the next moveend/zoomend event. Fixes greptile-apps review comments: - 3036106846 (P0): WARN_THRESHOLD not in scope - 3036106896 (P1): showLayerWarning() wrong message - 3036106953 (P2): layer not immediately removed
The debounced rebuild leaves a 150ms window where the broken layer is still in deck.gl's picking pipeline. A hover/click during that window can trigger the same crash this PR prevents. Use immediate setProps instead.
Summary
Prevents the desktop app from crashing when the deck.gl satellite imagery layer's stroke fragment shader fails to compile on Intel integrated GPUs (Intel i-series with integrated graphics on Windows 11).
Root cause
The fragment shader
satellite-imagery-layer-stroke-fragmentfails to compile on Intel integrated GPUs. The existingonErrorhandler only caughtapt-groups-layererrors, so this unhandled shader compilation error caused the app to crash.Changes
onErrorhandler to catchsatellite-imagery-layererrors and setsatelliteImageryLayerFailed = true. When this flag is set, the satellite imagery layer is skipped inbuildLayers()— matching the existing pattern used forapt-groups-layer. Also callsshowLayerWarning()so users understand why satellite imagery disappeared.Testing
apt-groups-layerCloses #2518