Skip to content

Real-device WebGPU crash in directional shadow receiver path after Three shadow render completion #333

Description

@tgabereal

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:
    • circle
    • plane
    • ring

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

Activity

  1. wcandillon commented on Mar 11, 2026

    @wcandillon
    Owner

    I would be interested to see the crash. do you have an error/stack trace?

  2. tgabereal commented on Mar 11, 2026

    @tgabereal
    Author

    Yes I reduced it further and made a standalone public repro:

    https://github.com/tgabereal/rnwgpu-shadow-receiver-repro

    Tested stack:

    • react-native-wgpu@0.5.8
    • three@0.183.2
    • @react-three/fiber@9.5.0
    • Expo 54 / React Native 0.81.5

    Current reduced condition:

    • the crash happens when receiveShadow = true and directionalShadow = true
    • if either side of that condition is removed, the repro passes

    Pass/fail matrix:

    • raw WebGPU repro: pass
    • raw Three WebGPU repro: pass
    • patched R3F WebGPU repro: pass
    • reduced shadow receiver repro: fail

    The failure is not tied to a specific material or ground geometry. It reproduces across:

    • materials: standard, lambert, basic
    • geometries: circle, plane, ring

    Real-device crash:

    • EXC_BAD_ACCESS (code=1, address=0x3ff8)
    • the top visible native frame in Xcode points at GPUCanvasContext::present()

    The best current classification from the repro work is:

    • during_shadow_pass_submission_before_native_present_completion

    Important context:

    • this reproduces on simulator and on a real iPhone
    • I also tried local three and react-native-wgpu patch candidates; none produced a complete fix
    • the only native patch that moved the boundary at all was a react-native-wgpu present/backend guard, but the reduced shadow repro still failed on real device

    If useful, I can also attach:

    1. the Xcode crash screenshot showing EXC_BAD_ACCESS at GPUCanvasContext::present()
    2. the reduced pass/fail matrix as JSON
    3. the exact minimal route/component from the repro repo
  3. wcandillon commented on Mar 11, 2026

    @wcandillon
    Owner

    It sounds like if I use the reproduction app on a real iphone, it should be "easy" to reproduce? I would be interested to see the stack trace but I can reproduce the issue, should be ok.

  4. tgabereal commented on Mar 11, 2026

    @tgabereal
    Author

    Yes, it reproduces reliably on a real iPhone.

    I tested it on an iPhone 16 Pro Max.

    The shortest path is:

    1. Install and run the app from the repro repo
    2. Open the reduced shadow receiver case
    3. Keep receiveShadow = true and directionalShadow = true
    4. The app terminates shortly after entering that scene

    If either of those conditions is removed, it passes.

    If helpful, I can also point to the exact repro component/route in the repo.

  5. tomtev commented on Apr 20, 2026

    @tomtev

    Does shadow work at all? Its freezing here and I dont see any examples about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions