빌드는 통과, 화면만 죽는 버그 — React 19·R3F ReactCurrentOwner 크래시 해결
가장 오래 붙잡은 버그는 정황부터 이상했다. npm run build는 멀쩡히 통과하고, 개발 서버도 200을 돌려주는데, 정작 브라우저 화면만 새하얗게 죽었다.
콘솔엔 딱 한 줄이 떠 있었다.
Uncaught TypeError: Cannot read properties of undefined (reading 'ReactCurrentOwner')
내 컴포넌트를 한참 의심했지만 거긴 멀쩡했다.
범인은 훨씬 아래, 라이브러리와 React 사이에 있었다.
진짜 원인: R3F v8과 React 19의 내부 API 불일치
React Three Fiber(R3F)는 React의 렌더 트리에 Three.js 객체를 끼워넣으려고 react-reconciler를 거쳐 React 내부 API를 직접 들여다본다.
그중 하나가 ReactCurrentOwner다.
문제는 R3F v8이 React 18 시절의 그 내부를 전제로 짜였다는 것.
React 19는 내부 구조를 갈아엎으면서 ReactCurrentOwner를 그 자리에서 치워버렸다.
그래서 R3F v8의 리콘실러가 초기화되는 순간 없는 속성을 읽고 — undefined.ReactCurrentOwner — 즉사한다.
여기에 Next.js가 기름을 부었다. Next 15·16은 React 19를 요구하고 함께 끌고 온다. 즉 Next 16 App Router로 올리는 순간 앱은 React 19 위에서 돌게 되는데, R3F만 v8에 머물러 있으면 정확히 이 충돌이 난다.
버전 궁합은 단순하다 — R3F v8은 React 18, R3F v9는 React 19.
drei(v9 → v10), postprocessing(v2 → v3)도 같은 React 19 라인에 맞춰 올라간다.
왜 빌드는 초록불이었나
이 크래시가 고약한 건 모든 정적 검사를 통과한다는 점이다.
- 타입체크·번들:
ReactCurrentOwner는__SECRET_INTERNALS…뒤에 숨은 런타임 내부 접근이다. TypeScript도 번들러도 "없는 속성"을 미리 잡아낼 방법이 없다.npm run build는 당연히 통과한다. - SSR·서버 200: 첫 응답은 페이지 셸을 그려 200으로 내려보낸다. R3F 리콘실러는 브라우저에서 캔버스를 마운트하는 순간 비로소 돌기 시작한다.
- 결과적으로 서버는 멀쩡, 클라이언트 하이드레이션에서만 터진다. 사용자는 흰 화면, 단서는 콘솔의 저 한 줄뿐.
빌드 통과와 서버 200은 "동작한다"의 증거가 못 된다.
런타임 호환성은 브라우저 콘솔까지 직접 봐야 안다 — 이게 이 버그가 남긴 제일 큰 교훈이다.
이 문제인지 30초 확인법
다음이 전부 맞으면 십중팔구 같은 원인이다.
- Next.js 15/16 App Router + React 19
@react-three/fiber가 아직 v8(= react 18용)에 머물러 있음- 콘솔에 정확히
reading 'ReactCurrentOwner'
npm ls react @react-three/fiber로 실제 설치된 버전을 찍어보면 한눈에 보인다 — react는 19인데 fiber가 8이면 그게 범인이다.
해결: 스택을 React 19 라인으로 정렬
고친 건 package.json 한 곳뿐이다. 게임 코드는 한 줄도 안 건드렸다.
- "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",
그다음 rm -rf node_modules package-lock.json && npm install로 깨끗이 다시 설치했다.
(반쪽 남은 옛 React가 트리에 끼어 "두 개의 React"가 되는 걸 확실히 막으려고.) 흰 화면은 그대로 살아났다.
버전 정렬, 그게 전부였다.
참고
- React 19 업그레이드 가이드 — 제거·변경된 내부 API
- React Three Fiber 설치 문서 — React 버전별 R3F 버전
- pmndrs/react-three-fiber #3398 — 같은
ReactCurrentOwner이슈
다음 편부터는 손맛을 만든 아케이드 물리로 넘어간다.
먼저 이동과 점프다.