#50067·expo

[expo-modules-jsi] SDK 57 local iOS build fails on Swift 6.2+: SWIFT_RETURNS_RETAINED on RuntimeScheduler constructors

Author: thiago-slbCreated Sep 11, 2026Updated Sep 17, 2026
Labelsneeds reviewcontributor: external

Minimal reproducible example

https://github.com/thiago-slb/expo-modules-jsi-swift62-repro

Summary

A blank SDK 57 app (create-expo-app --template blank, no app code changed) fails to build for iOS. Two constructors in expo-modules-jsi's RuntimeScheduler.h are annotated SWIFT_RETURNS_RETAINED, which Swift 6.2+ rejects:

node_modules/expo-modules-jsi/apple/Sources/ExpoModulesJSI-Cxx/include/RuntimeScheduler.h:53:26:
  error: 'RuntimeScheduler' cannot be annotated with either SWIFT_RETURNS_RETAINED or
  SWIFT_RETURNS_UNRETAINED because it is not returning a SWIFT_SHARED_REFERENCE type
  SWIFT_RETURNS_RETAINED RuntimeScheduler(void *scheduler, ScheduleFn fn) noexcept

node_modules/expo-modules-jsi/apple/Sources/ExpoModulesJSI-Cxx/include/RuntimeScheduler.h:61:26:
  error: (same)
  SWIFT_RETURNS_RETAINED RuntimeScheduler() {}

** BUILD FAILED **

Failing phase: [CP-User] Build ExpoModulesJSI xcframework.

The class does carry SWIFT_SHARED_REFERENCE, but only on the closing brace (line 90), while the annotated constructors are on lines 53 and 61. Swift 6.2+ rejects returns_retained on a constructor of an import_reference type.

expo-modules-jsi is not a direct dependency — it arrives via expo → expo-modules-core → expo-modules-jsi, so this affects every SDK 57 project doing local iOS builds on a machine with Swift 6.2+ (i.e. current Xcode).

Steps to reproduce

Platform: iOS, standalone/local build, package manager npm.

git clone https://github.com/thiago-slb/expo-modules-jsi-swift62-repro
cd expo-modules-jsi-swift62-repro
npm install
npx expo prebuild -p ios --no-install
cd ios && pod install
xcodebuild -workspace reprojsi.xcworkspace -scheme reprojsi \
  -configuration Release -sdk iphoneos -destination 'generic/platform=iOS' \
  CODE_SIGNING_ALLOWED=NO build

Expected: build succeeds. Actual: ** BUILD FAILED ** with the two errors above.

Already ruled out

  • Not a stale artifact. node_modules/expo-modules-jsi/apple/Products did not exist; the xcframework was built from scratch. Also reproduced after rm -rf ios and clearing ~/Library/Developer/Xcode/DerivedData.
  • Not fixed in the next major. npm pack [email protected], diffed against 57.1.0: the header is byte-for-byte identical, both annotations and the trailing SWIFT_SHARED_REFERENCE included.
  • Not declaration order. Moving SWIFT_SHARED_REFERENCE onto the class declaration (with forward declarations for the retain/release functions) makes the header compile standalone under clang++ -fsyntax-only, but the xcframework build fails identically.
  • Not fixed by a newer Xcode. Also reproduced on Xcode 26.6 / Apple Swift 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101). Newer Swift is stricter, not looser.

The macros come from <swift/bridging> in the active toolchain, with _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr) true — these are the real attribute definitions, not the empty fallbacks.

Workaround

EAS cloud builds succeed, so the build image ships a Swift older than 6.2. Only local builds are blocked.

Environment

  expo-env-info 2.1.0 environment info:
    System:
      OS: macOS 15.7.5
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 22.22.3
      Yarn: 1.22.22
      npm: 10.9.8
      Watchman: 2026.06.01.00
    Managers:
      CocoaPods: 1.16.2
    SDKs:
      iOS SDK:
        Platforms: DriverKit 25.2, iOS 26.2, macOS 26.2, tvOS 26.2, visionOS 26.2, watchOS 26.2
    IDEs:
      Android Studio: 2025.3 AI-253.32098.37.2534.15232325
      Xcode: 26.3/17C529 - /usr/bin/xcodebuild
    Expo Workflow: managed

expo 57.0.22 · expo-modules-jsi 57.1.0 · react-native 0.86.3 · Apple Swift 6.2.4 (swiftlang-6.2.4.1.4 clang-1700.6.4.2)

(Previously filed as #50061 and #50062, both auto-closed for lack of a linked repro — this one has the repository.)