Description
On 0.86 a pod that is built as a framework module (use_frameworks!) cannot include <React/…> from a public header. As soon as another pod imports it as a module, the build fails:
error: include of non-modular header inside framework module 'ReproPod.ReproPod':
'Pods/Headers/Public/React-Core/React/RCTBridge.h'
[-Werror,-Wnon-modular-include-in-framework-module]
This is not specific to any one library — it affects any native module whose public header does #import <React/…>, which is the norm. In our app 36 packages in node_modules do it.
Why
Up to 0.85, React-Core was compiled from source as a framework, so <React/X.h> resolved inside that framework and was modular.
0.86 serves it prebuilt, and inside React.xcframework/Headers the files live under React_Core/React/… — so <React/X.h> no longer resolves through the framework. The only route left is the flat symlink farm CocoaPods generates from React-Core.podspec (s.header_dir = "React", line 56) at Pods/Headers/Public/React-Core/React/: 278 symlinks into node_modules/react-native/, covered by no modulemap.
The include still resolves — just to a non-modular header, which Clang rejects inside a framework module.
React-VFS.yaml does map React/X.h into the xcframework, and the compile lines do carry -ivfsoverlay. But the overlay's only root is React.xcframework/Headers, and no -I points there. In the failing build of the reproducer:
-I …/Pods/Headers/Public/React-Core ← the flat farm; this is what wins
-I …/Pods/Headers/Public/React-Core-prebuilt ← contains React_Core/, React_jsi/… but no React/
(zero -I pointing at React.xcframework/Headers)
Three ingredients are required
Worth stating, because with only the first two the build passes and it looks like there is no bug:
use_frameworks! — the pod becomes a framework module
- a public header doing
#import <React/…>
- another pod importing it as a module — this is what triggers the
PrecompileModule step where the diagnostic fires
With no consumer, no PrecompileModule step runs for that pod. That is why the real-world reports come from packages that ship more than one pod: @react-native-firebase/messaging imports @react-native-firebase/app.
Expected
A pod built as a framework module can include <React/…> from a public header, as it could on 0.85 and earlier.
Actual
-Werror,-Wnon-modular-include-in-framework-module, because the include resolves to the flat symlink farm instead of the framework.
What we tried
Listing these because two of them look like the obvious fix and are not:
:modular_headers => true on React-Core — no-op. React-Core is already modular (the CocoaPods modulemap and the xcframework's own) and is not built from source, so the option has nothing to modularize.
- Removing the flat farm so the framework wins — the non-modular error goes away and resolution breaks outright:
'React/RCTBridge.h' file not found in every third-party pod. The farm is not a redundant copy; it is the only route.
- Suppressing the diagnostic (
-Wno-non-modular-include-in-framework-module across pod and aggregate xcconfigs) — the flag applies and every non-modular error disappears, but the module it produces is malformed. In our app, consumers then failed with declaration of 'RCTPromiseRejectBlock' must be imported from module '…' before it is required and unknown type name 'RCT_EXTERN'. We note 0.86 already contains fixes in this area (loading RCTDefines.h first in the prebuilt umbrella, dropping the module * wildcard) and that our installed modulemap has them — the problem persists past them.
- Forcing affected pods to build as static libraries — works, and is what we shipped. As far as we can tell it is also what Expo's autolinking does. But it means every app on
use_frameworks! has to carry a Podfile hook to compensate.
Suggested direction
Either would remove the need for a workaround:
- Have the prebuilt xcframework expose headers so
<React/X.h> resolves within the framework (not nested under React_Core/), or make the VFS overlay reachable from the header search paths pods actually receive.
- Do not emit the flat
Headers/Public/React-Core/React/ farm when React-Core is consumed prebuilt, leaving the modular route as the only one.
Found and diagnosed by the mobile team at Revel while upgrading our app from 0.79.7 to 0.86.2. We are happy to test a candidate fix against a real app with 37 native modules under use_frameworks! :linkage => :static and report back.
Steps to reproduce
git clone https://github.com/jfbarea/rn86-use-frameworks-nonmodular-repro
cd rn86-use-frameworks-nonmodular-repro/ReproRN86
npm install && bundle install && cd ios
# fails
USE_FRAMEWORKS=static bundle exec pod install
xcodebuild -project Pods/Pods.xcodeproj -target ReproPodConsumer \
-sdk iphonesimulator -configuration Debug -arch arm64 build
# control — same project, same pods, no frameworks
bundle exec pod install
xcodebuild -project Pods/Pods.xcodeproj -target ReproPodConsumer \
-sdk iphonesimulator -configuration Debug -arch arm64 build
|
ReproPod product |
build |
USE_FRAMEWORKS=static |
ReproPod.framework |
FAILED (exit 65) |
| default |
libReproPod.a |
SUCCEEDED |
The reproducer is the stock 0.86.2 template plus two local pods of three files each, and two lines in the Podfile. No third-party dependency is involved.
React Native Version
0.86.2
Affected Platforms
Runtime - iOS
Output of npx @react-native-community/cli info
System:
OS: macOS 26.5.2
CPU: (10) arm64 Apple M5
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.16.0
npm: 11.10.0
Managers:
CocoaPods: 1.16.2 # the reproducer runs 1.15.2 via bundler
SDKs:
iOS SDK: iOS 26.5
Xcode: 17F113
Stacktrace or Logs
PrecompileModule .../ExplicitPrecompiledModules/ReproPod-58RA2NU6KF1C4I2XPDS3ZK4YM.scan
builtin-precompileModule .../ReproPod-58RA2NU6KF1C4I2XPDS3ZK4YM.scan
While building module 'ReproPod':
In file included from <module-includes>:1:
In file included from .../Pods/Target Support Files/ReproPod/ReproPod-umbrella.h:13:
.../ReproPod/ios/ReproPod.h:2:9: error: include of non-modular header inside framework
module 'ReproPod.ReproPod': '.../Pods/Headers/Public/React-Core/React/RCTBridge.h'
[-Werror,-Wnon-modular-include-in-framework-module]
2 | #import <React/RCTBridge.h>
| ^
1 error generated.
** BUILD FAILED **
The header search paths on that same failing invocation — note that the only React-Core
entry is the flat farm, and nothing points at the xcframework's own Headers:
-I .../Pods/Headers/Public
-I .../Pods/Headers/Public/React-Core
MANDATORY Reproducer
https://github.com/jfbarea/rn86-use-frameworks-nonmodular-repro
Screenshots and Videos
No response
Description
On 0.86 a pod that is built as a framework module (
use_frameworks!) cannot include<React/…>from a public header. As soon as another pod imports it as a module, the build fails:This is not specific to any one library — it affects any native module whose public header does
#import <React/…>, which is the norm. In our app 36 packages innode_modulesdo it.Why
Up to 0.85,
React-Corewas compiled from source as a framework, so<React/X.h>resolved inside that framework and was modular.0.86 serves it prebuilt, and inside
React.xcframework/Headersthe files live underReact_Core/React/…— so<React/X.h>no longer resolves through the framework. The only route left is the flat symlink farm CocoaPods generates fromReact-Core.podspec(s.header_dir = "React", line 56) atPods/Headers/Public/React-Core/React/: 278 symlinks intonode_modules/react-native/, covered by no modulemap.The include still resolves — just to a non-modular header, which Clang rejects inside a framework module.
React-VFS.yamldoes mapReact/X.hinto the xcframework, and the compile lines do carry-ivfsoverlay. But the overlay's only root isReact.xcframework/Headers, and no-Ipoints there. In the failing build of the reproducer:Three ingredients are required
Worth stating, because with only the first two the build passes and it looks like there is no bug:
use_frameworks!— the pod becomes a framework module#import <React/…>PrecompileModulestep where the diagnostic firesWith no consumer, no
PrecompileModulestep runs for that pod. That is why the real-world reports come from packages that ship more than one pod:@react-native-firebase/messagingimports@react-native-firebase/app.Expected
A pod built as a framework module can include
<React/…>from a public header, as it could on 0.85 and earlier.Actual
-Werror,-Wnon-modular-include-in-framework-module, because the include resolves to the flat symlink farm instead of the framework.What we tried
Listing these because two of them look like the obvious fix and are not:
:modular_headers => trueon React-Core — no-op. React-Core is already modular (the CocoaPods modulemap and the xcframework's own) and is not built from source, so the option has nothing to modularize.'React/RCTBridge.h' file not foundin every third-party pod. The farm is not a redundant copy; it is the only route.-Wno-non-modular-include-in-framework-moduleacross pod and aggregate xcconfigs) — the flag applies and every non-modular error disappears, but the module it produces is malformed. In our app, consumers then failed withdeclaration of 'RCTPromiseRejectBlock' must be imported from module '…' before it is requiredandunknown type name 'RCT_EXTERN'. We note 0.86 already contains fixes in this area (loadingRCTDefines.hfirst in the prebuilt umbrella, dropping themodule *wildcard) and that our installed modulemap has them — the problem persists past them.use_frameworks!has to carry a Podfile hook to compensate.Suggested direction
Either would remove the need for a workaround:
<React/X.h>resolves within the framework (not nested underReact_Core/), or make the VFS overlay reachable from the header search paths pods actually receive.Headers/Public/React-Core/React/farm when React-Core is consumed prebuilt, leaving the modular route as the only one.Found and diagnosed by the mobile team at Revel while upgrading our app from 0.79.7 to 0.86.2. We are happy to test a candidate fix against a real app with 37 native modules under
use_frameworks! :linkage => :staticand report back.Steps to reproduce
USE_FRAMEWORKS=staticReproPod.frameworklibReproPod.aThe reproducer is the stock 0.86.2 template plus two local pods of three files each, and two lines in the
Podfile. No third-party dependency is involved.React Native Version
0.86.2
Affected Platforms
Runtime - iOS
Output of
npx @react-native-community/cli infoStacktrace or Logs
MANDATORY Reproducer
https://github.com/jfbarea/rn86-use-frameworks-nonmodular-repro
Screenshots and Videos
No response