Real-device WebGPU crash in directional shadow receiver path after Three shadow render completion
Summary
We reduced a WebGPU crash in our React Native / Expo app to a small repro that fails on both iOS simulator and a real iPhone, but only when a directional-light shadow receiver path is active.
What is already proven:
- raw WebGPU passes on simulator and real device
- raw Three WebGPU passes on simulator and real device
- patched R3F WebGPU passes on simulator and real device
- the reduced shadow receiver repro fails on simulator and real device
three completes the shadow render path on the JS side
- the only local patch that materially changed the failure boundary was in
react-native-wgpu
- no safe local workaround is proven
Current best attribution:
- this does not look like a generic WebGPU, generic Three, or generic R3F failure
- this looks like a native/backend WebGPU failure on the
react-native-wgpu / Dawn / Metal path during the shadow-pass submission lifecycle
- our best current stage classification is:
during_shadow_pass_submission_before_native_present_completion
Environment
react-native-wgpu: 0.5.8
react-native: 0.81.5
expo: ~54.0.0
react: 19.1.0
three: 0.183.2
@react-three/fiber: 9.5.0
- real device used for confirmation: iPhone 16 Pro Max
Passing controls
These all pass on simulator and real device:
- raw WebGPU
- raw Three WebGPU
- patched R3F WebGPU
Failing reduced repro
The failing repro is a reduced scene with a directional light and a shadow receiver.
Final narrowed failing condition:
receiveShadow = true
directionalShadow = true
This still fails across:
- materials:
MeshStandardMaterial
MeshLambertMaterial
MeshBasicMaterial
- geometries:
So this is not just “standard material on a circle”.
Observed behavior
On a real iPhone:
- the reduced repro reaches route-ready
- the process is gone by the end of the probe window
- deeper native trace capture could not be flushed before failure from this environment
On simulator:
- the same reduced repro also fails
Important local findings
1. three is not the first failing layer anymore
Our engine-level source-debugging narrowed the boundary further:
three reaches/completes the shadow render path on the JS/engine side
- the remaining blocker appears after that, in the native/backend path
2. A react-native-wgpu patch was the only patch that materially changed the failure boundary
We tested several local patch candidates.
Only one materially changed behavior:
- a native present/backend guard in
react-native-wgpu
That candidate:
- made the reduced repro pass on simulator
- made broader Doorway validation scenes pass on simulator and real device
- but the reduced shadow repro still failed on real device in the clean confirmation rerun
This is why react-native-wgpu is now our primary issue target.
3. Warm-up / delayed shadow enable did not solve it
We also tested delayed shadow enable / warm-up gating.
Result:
- no usable effect on real device
- the reduced repro still failed before the gate meaningfully activated
Why we think this belongs here
At this point the evidence suggests:
- the reduced repro is valid
- generic WebGPU and generic Three/R3F are fine
- the failure is in the native/backend path specific to the shadow-pass lifecycle on this stack
- the only patch that moved the boundary at all was in
react-native-wgpu
That makes react-native-wgpu the primary owner to inspect next.
Primary ask
Can you advise where to inspect next in the native/backend path for this reduced real-device shadow-pass failure?
The most relevant current question is:
- why does the reduced directional-shadow receiver repro still die on real device after
three shadow render completion, even though a native/backend guard is enough to make broader validation surfaces pass?
If there is a specific Dawn / Metal / react-native-wgpu texture, render-pass, queue-submit, or present-adjacent path that matches this pattern, that is the highest-value direction for us.
If helpful, I can provide:
- the reduced repro surface
- machine-readable simulator vs real-device comparison outputs
- the exact local patch candidates we tested
Real-device WebGPU crash in directional shadow receiver path after Three shadow render completion
Summary
We reduced a WebGPU crash in our React Native / Expo app to a small repro that fails on both iOS simulator and a real iPhone, but only when a directional-light shadow receiver path is active.
What is already proven:
threecompletes the shadow render path on the JS sidereact-native-wgpuCurrent best attribution:
react-native-wgpu/ Dawn / Metal path during the shadow-pass submission lifecycleduring_shadow_pass_submission_before_native_present_completionEnvironment
react-native-wgpu:0.5.8react-native:0.81.5expo:~54.0.0react:19.1.0three:0.183.2@react-three/fiber:9.5.0Passing controls
These all pass on simulator and real device:
Failing reduced repro
The failing repro is a reduced scene with a directional light and a shadow receiver.
Final narrowed failing condition:
receiveShadow = truedirectionalShadow = trueThis still fails across:
MeshStandardMaterialMeshLambertMaterialMeshBasicMaterialSo this is not just “standard material on a circle”.
Observed behavior
On a real iPhone:
On simulator:
Important local findings
1.
threeis not the first failing layer anymoreOur engine-level source-debugging narrowed the boundary further:
threereaches/completes the shadow render path on the JS/engine side2. A
react-native-wgpupatch was the only patch that materially changed the failure boundaryWe tested several local patch candidates.
Only one materially changed behavior:
react-native-wgpuThat candidate:
This is why
react-native-wgpuis now our primary issue target.3. Warm-up / delayed shadow enable did not solve it
We also tested delayed shadow enable / warm-up gating.
Result:
Why we think this belongs here
At this point the evidence suggests:
react-native-wgpuThat makes
react-native-wgputhe primary owner to inspect next.Primary ask
Can you advise where to inspect next in the native/backend path for this reduced real-device shadow-pass failure?
The most relevant current question is:
threeshadow render completion, even though a native/backend guard is enough to make broader validation surfaces pass?If there is a specific Dawn / Metal /
react-native-wgputexture, render-pass, queue-submit, or present-adjacent path that matches this pattern, that is the highest-value direction for us.If helpful, I can provide: