expo: Can't run on device on iOS 17

Summary

I’m trying to use npx expo run:ios --device to run the development app on my iPhone. This worked fine on iOS 16 but has stopped working on iOS 17. Every time I run the command, it builds fine, starts the dev server then crashes with the following error:

✖ Complete 100%
CommandError: InvalidService: com.apple.debugserver (request: StartService)
Try reconnecting your device. You can also debug service logs with `export DEBUG=expo:xdl:ios:*`

I tried running it with the export DEBUG=expo:xdl:ios:* but it didn’t spit out any additional information. I can start the dev server after I run that command and get it to work but the error is getting annoying b/c it requires running a command, waiting for it to fail, then running another command to test anything on the device that requires native code changes.

What platform(s) does this occur on?

iOS

SDK Version

Expo 49

Environment

expo-env-info 1.0.5 environment info: System: OS: macOS 14.0 Shell: 3.2.57 - /bin/bash Binaries: Node: 20.5.1 - /usr/local/bin/node Yarn: 1.22.10 - /usr/local/bin/yarn npm: 9.8.1 - ~/.npm-global/bin/npm Watchman: 2023.04.10.00 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.3 - /Users/marcato15/.rbenv/shims/pod SDKs: iOS SDK: Platforms: DriverKit 23.0, iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0 Android SDK: API Levels: 29, 30, 31, 33 Build Tools: 28.0.3, 29.0.2, 30.0.2, 30.0.3, 31.0.0, 33.0.0, 33.0.0 System Images: android-30 | Google APIs Intel x86 Atom, android-33 | Google APIs ARM 64 v8a IDEs: Android Studio: 2021.2 AI-212.5712.43.2112.8609683 Xcode: 15.0/15A240d - /usr/bin/xcodebuild npmPackages: @expo/metro-config: ^0.7.1 => 0.7.1 expo: ^49.0.3 => 49.0.3 react: 18.2.0 => 18.2.0 react-dom: 18.2.0 => 18.2.0 react-native: 0.72.3 => 0.72.3 npmGlobalPackages: eas-cli: 3.16.0 expo-cli: 6.3.8 Expo Workflow: bare

Minimal reproducible example

https://github.com/marcato15/TestExpoBug

About this issue

  • Original URL
  • State: closed
  • Created 9 months ago
  • Reactions: 15
  • Comments: 41 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Found a workaround to make it work on a physical device.

  1. Run npx expo run:ios --device and select you device.
  2. Once the build fail, open another terminal and run npx expo run:ios to build it on your simulator.
  3. When the simulator built is ready, close the failed app on your physical device and open it again, then ✨magically✨ the physical device will connect to metro from the simulator built and the app will work.

This is very annoying obviously. Please Expo, fix this soon.

If i try the workaround the build fails with xcode error 65 when i want to run npx expo run:ios

⚠️ ld: Could not find or use auto-linked framework ‘CoreAudioTypes’ ❌ Undefined symbols for architecture arm64 ┌─ Symbol: facebook::react::LongLivedObjectCollection::add(std::__1::shared_ptrfacebook::react::LongLivedObject) const └─ Referenced from: facebook::react::CallbackWrapper::createWeak(facebook::jsi::Function&&, facebook::jsi::Runtime&, std::__1::shared_ptrfacebook::react::CallInvoker) in ExpoModulesCore(EXJSIUtils.o)

❌ ld: symbol(s) not found for architecture arm64

❌ clang: error: linker command failed with exit code 1 (use -v to see invocation)

This doesnt happen if i run the expo run:ios --device command but there i get the crash described above

Not going to lie, it’s a little concerning that this wasn’t on Expo’s radar because I have known about this issue for a month since I upgraded oses on my phone to test out app for compatibility issues. You’d think expo would have done the same as well and encountered such an immediate bug in the dev workflow that is probably the workflow for most people using expo.

same problem here after i updated my device to ios 17, and was forced to update to xcode 15. however it work if i run build from xcode it self. but when i do npx expo run:ios --device i get the same problem

This issue has not been fixed.

I’m using this workaround :

  • run npx expo run:ios --device
  • Then run expo start --dev-client
  • Then open your app installed on your device

DID NPT WORK FOR ME. I got an error message: CommandError: Failed to build iOS project. “xcodebuild” exited with error code 65.

then the errors are: ❌ (node_modules/expo-modules-core/ios/Swift/Classes/ClassComponent.swift:42:45)

40 | public override func build(appContext: AppContext) throws -> JavaScriptObject { 41 | let klass = try appContext.runtime.createClass(name) { [weak self, weak appContext] this, arguments in

42 | guard let self = self, let appContext else { | ^ variable binding in a condition requires an initializer 43 | // TODO: Throw an exception? (@tsapeta) 44 | return 45 | }

❌ (node_modules/expo-modules-core/ios/Swift/Functions/ConcurrentFunctionDefinition.swift:85:28)

83 | [weak appContext, weak self, name] this, args, resolve, reject in 84 |

85 | guard let appContext else { | ^ variable binding in a condition requires an initializer 86 | let exception = Exceptions.AppContextLost() 87 | return reject(exception.code, exception.description, nil) 88 | }

❌ (node_modules/expo-modules-core/ios/Swift/Functions/ConcurrentFunctionDefinition.swift:89:22)

87 | return reject(exception.code, exception.description, nil) 88 | }

89 | guard let self else { | ^ variable binding in a condition requires an initializer 90 | let exception = NativeFunctionUnavailableException(name) 91 | return reject(exception.code, exception.description, nil) 92 | }

❌ (node_modules/expo-modules-core/ios/Swift/Conversions.swift:165:23)

163 | return value.map { $0.toDictionary() } 164 | }

165 | if let appContext { | ^ variable binding in a condition requires an initializer 166 | if let value = value as? JavaScriptObjectBuilder { 167 | return try? value.build(appContext: appContext) 168 | }

❌ (node_modules/expo-modules-core/ios/Swift/JavaScriptFunction.swift:42:26)

40 | */ 41 | private func call(withArguments arguments: [Any] = [], asConstructor: Bool = false, usingThis this: JavaScriptObject? = nil) throws -> ReturnType {

42 | guard let appContext else { | ^ variable binding in a condition requires an initializer 43 | throw AppContextLostException() 44 | } 45 | let value = rawFunction.call(withArguments: arguments, thisObject: this, asConstructor: false)

❌ (node_modules/expo-modules-core/ios/Swift/JavaScriptUtils.swift:104:18)

102 | } 103 | // Add promise to the array of arguments if necessary.

104 | if let promise { | ^ variable binding in a condition requires an initializer 105 | result += [promise] 106 | } 107 | return result

❌ (node_modules/expo-modules-core/ios/Swift/Modules/ModuleDefinition.swift:71:24)

69 | let object = try super.build(appContext: appContext) 70 |

71 | if let viewManager { | ^ variable binding in a condition requires an initializer 72 | let reactComponentPrototype = try appContext.runtime.createObject() 73 | try viewManager.decorateWithFunctions(object: reactComponentPrototype, appContext: appContext) 74 | object.setProperty(“ViewPrototype”, value: reactComponentPrototype)

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:65:26)

63 | 64 | func call(function functionName: String, args: [Any], _ callback: @escaping (FunctionCallResult) -> () = { _ in }) {

65 | guard let appContext else { | ^ variable binding in a condition requires an initializer 66 | callback(.failure(Exceptions.AppContextLost())) 67 | return 68 | }

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:78:25)

76 | @discardableResult 77 | func callSync(function functionName: String, args: [Any]) -> Any? {

78 | guard let appContext, let function = definition.functions[functionName] as? AnySyncFunctionComponent else { | ^ variable binding in a condition requires an initializer 79 | return nil 80 | } 81 | do {

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:105:26)

103 | private func createJavaScriptModuleObject() -> JavaScriptObject? { 104 | // It might be impossible to create any object at the moment (e.g. remote debugging, app context destroyed)

105 | guard let appContext else { | ^ variable binding in a condition requires an initializer 106 | return nil 107 | } 108 | do {

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:143:26)

141 | */ 142 | func modifyListenersCount(_ count: Int) {

143 | guard let appContext else { | ^ variable binding in a condition requires an initializer 144 | return 145 | } 146 | if count > 0 && listenersCount == 0 {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:138:28)

136 | internal func buildGetter(appContext: AppContext) throws -> JavaScriptObject { 137 | return try appContext.runtime.createSyncFunction(name, argsCount: 0) { [weak appContext, weak self, name] this, args in

138 | guard let appContext else { | ^ variable binding in a condition requires an initializer 139 | throw Exceptions.AppContextLost() 140 | } 141 | guard let self else {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:141:22)

139 | throw Exceptions.AppContextLost() 140 | }

141 | guard let self else { | ^ variable binding in a condition requires an initializer 142 | throw NativePropertyUnavailableException(name) 143 | } 144 | guard let getter = self.getter else {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:156:28)

154 | internal func buildSetter(appContext: AppContext) throws -> JavaScriptObject { 155 | return try appContext.runtime.createSyncFunction(name, argsCount: 1) { [weak appContext, weak self, name] this, args in

156 | guard let appContext else { | ^ variable binding in a condition requires an initializer 157 | throw Exceptions.AppContextLost() 158 | } 159 | guard let self else {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:159:22)

157 | throw Exceptions.AppContextLost() 158 | }

159 | guard let self else { | ^ variable binding in a condition requires an initializer 160 | throw NativePropertyUnavailableException(name) 161 | } 162 | guard let setter = self.setter else {

❌ (node_modules/expo-modules-core/ios/Swift/Functions/SyncFunctionComponent.swift:101:28)

99 | // the native definition instance deallocates correctly when the JS VM triggers the garbage collector. 100 | return try appContext.runtime.createSyncFunction(name, argsCount: argumentsCount) { [weak appContext, self] this, args in

101 | guard let appContext else { | ^ variable binding in a condition requires an initializer 102 | throw Exceptions.AppContextLost() 103 | } 104 | let result = try self.call(by: this, withArguments: args, appContext: appContext)

❌ (node_modules/expo-modules-core/ios/Swift/DynamicTypes/DynamicEnumType.swift:7:22)

5 | */ 6 | internal struct DynamicEnumType: AnyDynamicType {

7 | let innerType: any Enumerable.Type | ^ protocol ‘Enumerable’ can only be used as a generic constraint because it has Self or associated type requirements 8 | 9 | func wraps<InnerType>(_ type: InnerType.Type) -> Bool { 10 | return innerType == InnerType.self

❌ (node_modules/expo-modules-core/ios/Swift/DynamicTypes/DynamicType.swift:21:36)

19 | return DynamicConvertibleType(innerType: ConvertibleType) 20 | }

21 | if let EnumType = T.self as? any Enumerable.Type { | ^ protocol ‘Enumerable’ can only be used as a generic constraint because it has Self or associated type requirements 22 | return DynamicEnumType(innerType: EnumType) 23 | } 24 | if let ViewType = T.self as? UIView.Type {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:144:31)

142 | throw NativePropertyUnavailableException(name) 143 | }

144 | guard let getter = self.getter else { | ^ type of expression is ambiguous without more context 145 | return 146 | } 147 | return try getter.call(by: this, withArguments: args, appContext: appContext)

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:145:9)

143 | } 144 | guard let getter = self.getter else {

145 | return | ^ non-void function should return a value 146 | } 147 | return try getter.call(by: this, withArguments: args, appContext: appContext) 148 | }

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:162:31)

160 | throw NativePropertyUnavailableException(name) 161 | }

162 | guard let setter = self.setter else { | ^ type of expression is ambiguous without more context 163 | return 164 | } 165 | return try setter.call(by: this, withArguments: args, appContext: appContext)

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:163:9)

161 | } 162 | guard let setter = self.setter else {

163 | return | ^ non-void function should return a value 164 | } 165 | return try setter.call(by: this, withArguments: args, appContext: appContext) 166 | }

❌ (node_modules/expo-modules-core/ios/Swift/Functions/SyncFunctionComponent.swift:105:14)

103 | } 104 | let result = try self.call(by: this, withArguments: args, appContext: appContext)

105 | return Conversions.convertFunctionResult(result, appContext: appContext, dynamicType: ~ReturnType.self) | ^ generic parameter ‘ValueType’ could not be inferred 106 | } 107 | } 108 | }

Hopefully Apple or expo can get this fixed.

This issue has not been fixed.

I’m using this workaround :

  • run npx expo run:ios --device
  • Then run expo start --dev-client
  • Then open your app installed on your device

This issue has not been fixed. I’m using this workaround :

  • run npx expo run:ios --device
  • Then run expo start --dev-client
  • Then open your app installed on your device

DID NPT WORK FOR ME. I got an error message: CommandError: Failed to build iOS project. “xcodebuild” exited with error code 65.

then the errors are: ❌ (node_modules/expo-modules-core/ios/Swift/Classes/ClassComponent.swift:42:45)

40 | public override func build(appContext: AppContext) throws -> JavaScriptObject { 41 | let klass = try appContext.runtime.createClass(name) { [weak self, weak appContext] this, arguments in

42 | guard let self = self, let appContext else { | ^ variable binding in a condition requires an initializer 43 | // TODO: Throw an exception? (@tsapeta) 44 | return 45 | }

❌ (node_modules/expo-modules-core/ios/Swift/Functions/ConcurrentFunctionDefinition.swift:85:28)

83 | [weak appContext, weak self, name] this, args, resolve, reject in 84 |

85 | guard let appContext else { | ^ variable binding in a condition requires an initializer 86 | let exception = Exceptions.AppContextLost() 87 | return reject(exception.code, exception.description, nil) 88 | }

❌ (node_modules/expo-modules-core/ios/Swift/Functions/ConcurrentFunctionDefinition.swift:89:22)

87 | return reject(exception.code, exception.description, nil) 88 | }

89 | guard let self else { | ^ variable binding in a condition requires an initializer 90 | let exception = NativeFunctionUnavailableException(name) 91 | return reject(exception.code, exception.description, nil) 92 | }

❌ (node_modules/expo-modules-core/ios/Swift/Conversions.swift:165:23)

163 | return value.map { $0.toDictionary() } 164 | }

165 | if let appContext { | ^ variable binding in a condition requires an initializer 166 | if let value = value as? JavaScriptObjectBuilder { 167 | return try? value.build(appContext: appContext) 168 | }

❌ (node_modules/expo-modules-core/ios/Swift/JavaScriptFunction.swift:42:26)

40 | */ 41 | private func call(withArguments arguments: [Any] = [], asConstructor: Bool = false, usingThis this: JavaScriptObject? = nil) throws -> ReturnType {

42 | guard let appContext else { | ^ variable binding in a condition requires an initializer 43 | throw AppContextLostException() 44 | } 45 | let value = rawFunction.call(withArguments: arguments, thisObject: this, asConstructor: false)

❌ (node_modules/expo-modules-core/ios/Swift/JavaScriptUtils.swift:104:18)

102 | } 103 | // Add promise to the array of arguments if necessary.

104 | if let promise { | ^ variable binding in a condition requires an initializer 105 | result += [promise] 106 | } 107 | return result

❌ (node_modules/expo-modules-core/ios/Swift/Modules/ModuleDefinition.swift:71:24)

69 | let object = try super.build(appContext: appContext) 70 |

71 | if let viewManager { | ^ variable binding in a condition requires an initializer 72 | let reactComponentPrototype = try appContext.runtime.createObject() 73 | try viewManager.decorateWithFunctions(object: reactComponentPrototype, appContext: appContext) 74 | object.setProperty(“ViewPrototype”, value: reactComponentPrototype)

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:65:26)

63 | 64 | func call(function functionName: String, args: [Any], _ callback: @escaping (FunctionCallResult) -> () = { _ in }) {

65 | guard let appContext else { | ^ variable binding in a condition requires an initializer 66 | callback(.failure(Exceptions.AppContextLost())) 67 | return 68 | }

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:78:25)

76 | @discardableResult 77 | func callSync(function functionName: String, args: [Any]) -> Any? {

78 | guard let appContext, let function = definition.functions[functionName] as? AnySyncFunctionComponent else { | ^ variable binding in a condition requires an initializer 79 | return nil 80 | } 81 | do {

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:105:26)

103 | private func createJavaScriptModuleObject() -> JavaScriptObject? { 104 | // It might be impossible to create any object at the moment (e.g. remote debugging, app context destroyed)

105 | guard let appContext else { | ^ variable binding in a condition requires an initializer 106 | return nil 107 | } 108 | do {

❌ (node_modules/expo-modules-core/ios/Swift/ModuleHolder.swift:143:26)

141 | */ 142 | func modifyListenersCount(_ count: Int) {

143 | guard let appContext else { | ^ variable binding in a condition requires an initializer 144 | return 145 | } 146 | if count > 0 && listenersCount == 0 {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:138:28)

136 | internal func buildGetter(appContext: AppContext) throws -> JavaScriptObject { 137 | return try appContext.runtime.createSyncFunction(name, argsCount: 0) { [weak appContext, weak self, name] this, args in

138 | guard let appContext else { | ^ variable binding in a condition requires an initializer 139 | throw Exceptions.AppContextLost() 140 | } 141 | guard let self else {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:141:22)

139 | throw Exceptions.AppContextLost() 140 | }

141 | guard let self else { | ^ variable binding in a condition requires an initializer 142 | throw NativePropertyUnavailableException(name) 143 | } 144 | guard let getter = self.getter else {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:156:28)

154 | internal func buildSetter(appContext: AppContext) throws -> JavaScriptObject { 155 | return try appContext.runtime.createSyncFunction(name, argsCount: 1) { [weak appContext, weak self, name] this, args in

156 | guard let appContext else { | ^ variable binding in a condition requires an initializer 157 | throw Exceptions.AppContextLost() 158 | } 159 | guard let self else {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:159:22)

157 | throw Exceptions.AppContextLost() 158 | }

159 | guard let self else { | ^ variable binding in a condition requires an initializer 160 | throw NativePropertyUnavailableException(name) 161 | } 162 | guard let setter = self.setter else {

❌ (node_modules/expo-modules-core/ios/Swift/Functions/SyncFunctionComponent.swift:101:28)

99 | // the native definition instance deallocates correctly when the JS VM triggers the garbage collector. 100 | return try appContext.runtime.createSyncFunction(name, argsCount: argumentsCount) { [weak appContext, self] this, args in

101 | guard let appContext else { | ^ variable binding in a condition requires an initializer 102 | throw Exceptions.AppContextLost() 103 | } 104 | let result = try self.call(by: this, withArguments: args, appContext: appContext)

❌ (node_modules/expo-modules-core/ios/Swift/DynamicTypes/DynamicEnumType.swift:7:22)

5 | */ 6 | internal struct DynamicEnumType: AnyDynamicType {

7 | let innerType: any Enumerable.Type | ^ protocol ‘Enumerable’ can only be used as a generic constraint because it has Self or associated type requirements 8 | 9 | func wraps(_ type: InnerType.Type) -> Bool { 10 | return innerType == InnerType.self

❌ (node_modules/expo-modules-core/ios/Swift/DynamicTypes/DynamicType.swift:21:36)

19 | return DynamicConvertibleType(innerType: ConvertibleType) 20 | }

21 | if let EnumType = T.self as? any Enumerable.Type { | ^ protocol ‘Enumerable’ can only be used as a generic constraint because it has Self or associated type requirements 22 | return DynamicEnumType(innerType: EnumType) 23 | } 24 | if let ViewType = T.self as? UIView.Type {

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:144:31)

142 | throw NativePropertyUnavailableException(name) 143 | }

144 | guard let getter = self.getter else { | ^ type of expression is ambiguous without more context 145 | return 146 | } 147 | return try getter.call(by: this, withArguments: args, appContext: appContext)

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:145:9)

143 | } 144 | guard let getter = self.getter else {

145 | return | ^ non-void function should return a value 146 | } 147 | return try getter.call(by: this, withArguments: args, appContext: appContext) 148 | }

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:162:31)

160 | throw NativePropertyUnavailableException(name) 161 | }

162 | guard let setter = self.setter else { | ^ type of expression is ambiguous without more context 163 | return 164 | } 165 | return try setter.call(by: this, withArguments: args, appContext: appContext)

❌ (node_modules/expo-modules-core/ios/Swift/Objects/PropertyComponent.swift:163:9)

161 | } 162 | guard let setter = self.setter else {

163 | return | ^ non-void function should return a value 164 | } 165 | return try setter.call(by: this, withArguments: args, appContext: appContext) 166 | }

❌ (node_modules/expo-modules-core/ios/Swift/Functions/SyncFunctionComponent.swift:105:14)

103 | } 104 | let result = try self.call(by: this, withArguments: args, appContext: appContext)

105 | return Conversions.convertFunctionResult(result, appContext: appContext, dynamicType: ~ReturnType.self) | ^ generic parameter ‘ValueType’ could not be inferred 106 | } 107 | } 108 | }

Hopefully Apple or expo can get this fixed.

Just got the exact same error after trying to run my app on iOS for the first time after months of developing only on my Android simulator. expo-doctor returns no errors, not sure what to do.

While upgrading might fix this very basic problem, Expo is supposed to – according to the version upgrade docs – be supported a couple trailing versions of their platform. Upgrading isn’t always fast or easy, especially when there are internal (e.g. corporate) validation processes in place for major upgrades.

This issue has not been fixed. Please re-open.

@byCedric thanks. Will this change be merged for Expo 47 and 48? (Seems like a fairly critical issue and these versions are supposed to be supported still I believe – we can’t upgrade from 47 for at least a few months)

Workaround is available in expo@49.0.13, install this issue and let me know if it still doesn’t work for you.

@Libero793 the workaround should be available soon through a patch update in expo. Once it out, I’ll post it here.

I can run on simulator, but on device it never connect to metro, no matter what I do 😦