Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS network crash #6400

Open
edenman opened this issue Mar 3, 2025 · 5 comments
Open

iOS network crash #6400

edenman opened this issue Mar 3, 2025 · 5 comments

Comments

@edenman
Copy link
Contributor

edenman commented Mar 3, 2025

Version

4.0.1

Summary

I filed this before but don't have permission to re-open #6201 and we got a little more info. Here's the stack:

Exception doesn't match @Throws-specified class list and thus isn't propagated from Kotlin to Objective-C/Swift as NSError.
It is considered unexpected and unhandled instead. Program will be terminated.
Uncaught Kotlin exception: com.apollographql.apollo.exception.ApolloNetworkException: Failed to execute GraphQL http network request
    at 0   NetworkCrash.debug.dylib            0x106878143        kfun:kotlin.Exception#<init>(kotlin.String?;kotlin.Throwable?){} + 143 
    at 1   NetworkCrash.debug.dylib            0x106878363        kfun:kotlin.RuntimeException#<init>(kotlin.String?;kotlin.Throwable?){} + 143 
    at 2   NetworkCrash.debug.dylib            0x106a9060f        kfun:com.apollographql.apollo.exception.ApolloException#<init>(kotlin.String?;kotlin.Throwable?){} + 123 
    at 3   NetworkCrash.debug.dylib            0x106a90ad7        kfun:com.apollographql.apollo.exception.ApolloNetworkException#<init>(kotlin.String?;kotlin.Any?){} + 239 
    at 4   NetworkCrash.debug.dylib            0x106b3d603        kfun:com.apollographql.apollo.network.http.buildHttpResponse#internal + 731 
    at 5   NetworkCrash.debug.dylib            0x106b3d167        kfun:com.apollographql.apollo.network.http.AppleHttpEngine.object-1.onComplete#internal + 263 
    at 6   NetworkCrash.debug.dylib            0x106b792bb        kfun:com.apollographql.apollo.network.http.StreamingDataDelegate.Handler.com.apollographql.apollo.network.http.StreamingDataDelegate.Handler#onComplete(platform.Foundation.NSError?){}-trampoline + 99 
    at 7   NetworkCrash.debug.dylib            0x106b3e3df        kfun:com.apollographql.apollo.network.http.StreamingDataDelegate.URLSession#internal.3 + 311 
    at 8   NetworkCrash.debug.dylib            0x106b40753        _636f6d2e61706f6c6c6f6772617068716c2e61706f6c6c6f3a61706f6c6c6f2d72756e74696d652f55736572732f72756e6e65722f776f726b2f61706f6c6c6f2d6b6f746c696e2f61706f6c6c6f2d6b6f746c696e2f6c69627261726965732f61706f6c6c6f2d72756e74696d652f7372632f6170706c654d61696e2f6b6f746c696e2f636f6d2f61706f6c6c6f6772617068716c2f61706f6c6c6f2f6e6574776f726b2f687474702f44656661756c7448747470456e67696e652e6170706c652e6b74_knbridge43 + 275 
    at 9   CFNetwork                           0x18887ee13        <redacted> + 35 
    at 10  libdispatch.dylib                   0x10583088b        _dispatch_call_block_and_release + 31 
    at 11  libdispatch.dylib                   0x105832577        _dispatch_client_callout + 19 
    at 12  libdispatch.dylib                   0x10583a453        _dispatch_lane_serial_drain + 839 
    at 13  libdispatch.dylib                   0x10583b28f        _dispatch_lane_invoke + 459 
    at 14  libdispatch.dylib                   0x1058486fb        _dispatch_root_queue_drain_deferred_wlh + 327 
    at 15  libdispatch.dylib                   0x105847d0b        _dispatch_workloop_worker_thread + 579 
    at 16  libsystem_pthread.dylib             0x21212c67f        _pthread_wqthread + 287 
    at 17  libsystem_pthread.dylib             0x21212a473        start_wqthread + 7 

None of our app's code is involved afaict. Does ApolloCall.execute need a @Throws annotation to keep ios from crashing?

Steps to reproduce the behavior

No response

Logs

(Your logs here)
@martinbonnin
Copy link
Contributor

martinbonnin commented Mar 3, 2025

Does ApolloCall.execute need a @throws annotation to keep ios from crashing?

Looks like it... Maybe it's somewhere deeper though as execute() shouldn't throw itself. But some parts of HttpNetworkEngine definely throw (and are caught to be exposed in response.exception).

I think I tried last time in a sample app and wasn't able to reproduce. Does that happen every time for you?

@iMinichrispy
Copy link

Specifically, we're seeing the issue when we have Airplane Mode enabled and we add Swift interceptors to the Apollo client. If the interceptors are defined in our KMP xcframework instead, the issue is resolved.

Our setup in Swift is along the lines of this:

let httpNetworkTransport = Apollo_runtimeHttpNetworkTransport.Builder()
    .interceptors(interceptors: [AuthenticationInterceptor()])
    .build()

// `KMPApolloClientBuilder` is defined in KMP xcframework
let apolloClient: ApolloClient = KMPApolloClientBuilder.build(httpNetworkTransport: httpNetworkTransport)

final class AuthenticationInterceptor: Apollo_runtimeHttpInterceptor {

    func intercept(request: Apollo_apiHttpRequest, chain: Apollo_runtimeHttpInterceptorChain) async throws -> Apollo_apiHttpResponse {
        // TODO: Add Auth headers
        return try await chain.proceed(request: request)
    }
    
    func dispose() {
        // No op
    }
}

Will try and get an end to end sample project together this week that reproduces the exact issue.

@martinbonnin
Copy link
Contributor

martinbonnin commented Mar 4, 2025

I can reproduce here but sadly don't have a great solution so far.

The contract of HttpInterceptor.intercept() is to throw ApolloException, which looks like it's pretty hard to do from the Swift side of things. Reading issues like https://youtrack.jetbrains.com/issue/KT-53004, looks like there might be a possibility to catch a ForeignException that you may be able to wrap from another wrapping interceptor but not 100% how (if) that's going to work.

@edenman
Copy link
Contributor Author

edenman commented Mar 10, 2025

This would be a pain, but could we change HttpInterceptor.intercept() to return a Result<HttpResponse> so we just avoid this entirely?

@martinbonnin
Copy link
Contributor

@edenman I managed to make exceptions work by broadening the possible exceptions from HttpInterceptor.intercept() to Throwable. See https://github.com/apollographql/apollo-kotlin/pull/6403/files#diff-8de6de1a056a0a0131bf7ad89d9e8dc7bde74511ef0d2acda2c22cb8dca2f41cR26

The exception arrives in Kotlin-land as a ObjCErrorException, which is mostly internal but if you really need to get information from it, https://github.com/rickclephas/NSErrorKt should help.

I'll give it a couple of days to settle, make sure this does not disrupt existing users too much but I think it should be acceptable. Let me know if that'd work for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants