Build passes, blank screen: fixing the React 19 'ReactCurrentOwner' crash in Next.js + React Three Fiber
The bug I wrestled with longest had bizarre symptoms. npm run build passed cleanly, the dev server returned 200, and yet the browser screen went stark white and died.
The console held a single line.
Uncaught TypeError: Cannot read properties of undefined (reading 'ReactCurrentOwner')
I suspected my own components for a long time, but they were fine.
The culprit was much further down — between the library and React itself.
The real cause: a R3F v8 vs. React 19 internal-API mismatch
React Three Fiber (R3F) splices Three.js objects into React's render tree through react-reconciler, which reaches into React's internal APIs.
One of those is ReactCurrentOwner.
The problem: R3F v8 was written against React 18's internals. React 19 reorganized those internals and removed ReactCurrentOwner from where it used to live.
So the moment R3F v8's reconciler initializes, it reads a property that no longer exists — undefined.ReactCurrentOwner — and dies.
Next.js poured fuel on the fire. Next 15 and 16 require, and pull in, React 19. The instant you move to the Next 16 App Router your app runs on React 19 — and if R3F is still on v8, you get exactly this crash.
The pairing is simple — R3F v8 goes with React 18, R3F v9 with React 19.
drei (v9 → v10) and postprocessing (v2 → v3) move onto the same React 19 line too.
Why the build was green
What makes this crash nasty is that it passes every static check.
- Type-check & bundling:
ReactCurrentOwneris a runtime access hidden behind__SECRET_INTERNALS…. Neither TypeScript nor the bundler can flag a "missing property" ahead of time, sonpm run buildpasses. - SSR & a 200 from the server: the first response renders the page shell and returns 200. R3F's reconciler only starts running the moment the canvas mounts in the browser.
- The net result: the server is fine, and it only blows up at client hydration. The user sees a white screen; the only clue is that one console line.
A passing build and a 200 from the server are no proof that something "works." Runtime compatibility is something you only learn by looking at the browser console yourself — the biggest takeaway from this bug.
A 30-second check for whether this is you
If all three are true, it's almost certainly the same cause:
- Next.js 15/16 App Router + React 19
@react-three/fiberis still on v8 (the react 18 line)- The console says exactly
reading 'ReactCurrentOwner'
Run npm ls react @react-three/fiber to print the actually-installed versions — if react is 19 but fiber is 8, that's your culprit.
The fix: line the stack up on React 19
I changed one file, package.json. Not a single line of game code.
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
- "@react-three/fiber": "^8.17.10",
- "@react-three/drei": "^9.122.0",
- "@react-three/postprocessing": "^2.16.3",
+ "react": "^19.2.7",
+ "react-dom": "^19.2.7",
+ "@react-three/fiber": "^9.6.1",
+ "@react-three/drei": "^10.7.7",
+ "@react-three/postprocessing": "^3.0.4",
Then a clean reinstall: rm -rf node_modules package-lock.json && npm install (to be sure no half-leftover old React lingers in the tree and creates a "two Reacts" situation).
The white screen came right back to life.
Aligning the versions was the whole fix.
References
- React 19 upgrade guide — removed/changed internal APIs
- React Three Fiber installation docs — which R3F version pairs with which React
- pmndrs/react-three-fiber #3398 — the same
ReactCurrentOwnerissue
From the next post on, I move to the arcade physics that gave the game its feel.
Movement and jumping first.