okhttp icon indicating copy to clipboard operation
okhttp copied to clipboard

v5.0.0-alpha16 - No virtual method getEventListenerFactory

Open AlexanderEggers opened this issue 6 months ago • 9 comments

After updating from v5.0.0-alpha14 to v5.0.0-alpha16, the release build of my android app is crashing with the following error:

NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class LJf/K; or its super classes (declaration of 'Jf.K' appears in /data/app/~~F8MgBq3JZu9FbBw49qQ8DQ==/com.myapp.release-N05Wr0CV4hKEqlty98x18g==/base.apk)

This works fine using debug builds, so likely an R8 issue if I have to guess.

AlexanderEggers avatar May 30 '25 06:05 AlexanderEggers

I get that on debug builds too

dawidhyzy avatar May 30 '25 14:05 dawidhyzy

Do you have a simple repro? Is it relatively recent Gradle, AGP etc?

yschimke avatar May 30 '25 19:05 yschimke

I don't have a repo, but I'm using gradle 8.14.1, kotlin 2.1.21, AGP 8.10.1. The project is also using wire (5.3.1) and retrofit (3.0.0).

AlexanderEggers avatar May 31 '25 01:05 AlexanderEggers

Yep, that seems quite modern.

I'll try to make a simple repro next week with a debug and release build and if I can't maybe get you to see what differs.

yschimke avatar May 31 '25 06:05 yschimke

Using com.squareup.okhttp3:okhttp-jvm instead of com.squareup.okhttp3:okhttp solved it for me, see https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-500-alpha15

WebTiger89 avatar Jun 06 '25 13:06 WebTiger89

That should be handled automatically for an android Gradle build or I assume maven.

Also if you need this workaround, make sure to use the android artifact on android builds

yschimke avatar Jun 06 '25 14:06 yschimke

Using com.squareup.okhttp3:okhttp-jvm instead of com.squareup.okhttp3:okhttp solved it for me, see https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-500-alpha15

I don't believe this is a workaround I want to consider given that I really want to use the android artifact, not just the jvm.

AlexanderEggers avatar Jun 06 '25 14:06 AlexanderEggers

I don't have an interesting repro, mainly because I can't get it failing with a debug or release build. or with the OkHttp android test app.

    @Singleton
    @Provides
    fun okhttpClient(
        cache: Cache,
        alwaysHttpsInterceptor: Interceptor,
    ): OkHttpClient {
        return OkHttpClient.Builder().followSslRedirects(false)
            .addInterceptor(alwaysHttpsInterceptor)
            .eventListenerFactory(LoggingEventListener.Factory())
            .cache(cache)
            .build()
            .apply { println("Using okhttp client " + this.eventListenerFactory) }
    }
Using okhttp client A3.e@b4f5a98

Can anyone provide a repro github project?

yschimke avatar Jun 06 '25 15:06 yschimke

I don't have an interesting repro, mainly because I can't get it failing with a debug or release build. or with the OkHttp android test app.

    @Singleton
    @Provides
    fun okhttpClient(
        cache: Cache,
        alwaysHttpsInterceptor: Interceptor,
    ): OkHttpClient {
        return OkHttpClient.Builder().followSslRedirects(false)
            .addInterceptor(alwaysHttpsInterceptor)
            .eventListenerFactory(LoggingEventListener.Factory())
            .cache(cache)
            .build()
            .apply { println("Using okhttp client " + this.eventListenerFactory) }
    }
Using okhttp client A3.e@b4f5a98

Can anyone provide a repro github project?

I don't use the eventListenerFactory directly, for example:

OkHttpClient.Builder().run {
        addDefaultHeadersInterceptor() // attaches certain headers to every request
        addDebugInterceptor() // used for logging responses in debug builds
        build()
    }

I will try to create a sample project in the next two weeks.

AlexanderEggers avatar Jun 07 '25 07:06 AlexanderEggers

@yschimke I did a bit more testing and I exclude all okhttp from my r8 rules and getting this full error:

java.lang.NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class Lokhttp3/OkHttpClient$Builder; or its super classes

Is there maybe a version conflict between retrofit, wire and okhttp?

AlexanderEggers avatar Jun 18 '25 14:06 AlexanderEggers

Can you include full stacktraces?

yschimke avatar Jun 18 '25 14:06 yschimke

Found the version conflict. LaunchDarkly seems to be causing issues with the latest alpha.

FATAL EXCEPTION: DefaultDispatcher-worker-1 Process: com.myapp, PID: 7485 java.lang.NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class Lokhttp3/OkHttpClient$Builder; or its super classes (declaration of 'okhttp3.OkHttpClient$Builder' appears in /data/app/~~HV1pzQaz2377sonUaOdLcQ==/com.myapp-1CWGCF1gGfQMzEHXGhCyCA==/base.apk!classes2.dex) at okhttp3.OkHttpClient.(OkHttpClient.kt:132) at okhttp3.OkHttpClient$Builder.build(OkHttpClient.kt:1384) at com.launchdarkly.sdk.android.HttpFeatureFlagFetcher.(HttpFeatureFlagFetcher.java:68) at com.launchdarkly.sdk.android.LDClient.(LDClient.java:335) at com.launchdarkly.sdk.android.LDClient.init(LDClient.java:164) at com.launchdarkly.sdk.android.LDClient.init(LDClient.java:238) at com.myapp.domain.featureflags.internal.LaunchDarklyClient$init$1.invokeSuspend(LaunchDarklyClient.kt:47) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100) at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:124) at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:820) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704) Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@9fcac2d, Dispatchers.IO]

AlexanderEggers avatar Jun 18 '25 15:06 AlexanderEggers

I don't think that points to LaunchDarkly. It says the initializer of OkHttpClient is trying to access a method on OkHttpClient$Builder which doesn't exist. This likely means you have two copies of OkHttp on your classpath and you are getting an OkHttpClient.class from one and OkHttpClient$Builder.class from the other, and they disagree on version.

JakeWharton avatar Jun 18 '25 15:06 JakeWharton

Thanks for your suggestion. I verified that I've got all my okhttp3 versions the same but the crash is still happening.

AlexanderEggers avatar Jun 18 '25 15:06 AlexanderEggers

You would have to check the runtime classpath of the dependencies task to see if there are multiple copies. Since OkHttp switched to being multiplatform, you could have something like okhttp-4.12.0.jar and okhttp-jvm-5.0.0-alpha16.jar both present, since the latter imposes no dependency constraint on the former.

I believe that will be the outcome of this bug, is the addition of a dependency constraint to ensure the "common" artifact has a version which matches the target-specific dependency.

JakeWharton avatar Jun 18 '25 15:06 JakeWharton

I have added

subprojects {
    configurations.all {
        resolutionStrategy {
            force("com.squareup.okhttp3:okhttp:5.0.0-alpha.16")
        }
    }
}

to my root build.gradle.kts file and verified that there is just alpha16 mentioned when checking the runtime classpath.

AlexanderEggers avatar Jun 18 '25 16:06 AlexanderEggers

@AlexanderEggers did this help you?

I still get java.lang.NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class Lokhttp3/OkHttpClient$Builder; or its super classes when OkHttpClient.Builder().build() is called.

dawidhyzy avatar Jun 20 '25 11:06 dawidhyzy

Unfortunately no, I'm still having the same issue.

AlexanderEggers avatar Jun 20 '25 12:06 AlexanderEggers

Can you run and post the output

./gradlew app:dependencies

yschimke avatar Jun 20 '25 14:06 yschimke

On this branch I’ve attempted a few combinations of OkHttp-including transitive dependencies:

  • LaunchDarkly, because it‘s mentioned here
  • Wire, because it is a multiplatform library that depends on OkHttp
  • Retrofit, because it is a non-multiplatform library that depends on OkHttp And target platforms:
  • Java
  • Android

Thus far I haven’t been able to reproduce this problem.

I would greatly appreciate some help reproducing this problem. I would like to fix this before releasing 5.0 final!

swankjesse avatar Jun 29 '25 15:06 swankjesse

On this commit, Gradle 8.10.1 resolved the right okhttp-android artifact, and only that one. I wonder what else I’m missing..

releaseRuntimeClasspath - Runtime classpath of '/release'.
+--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21
|    \--- org.jetbrains:annotations:13.0 -> 23.0.0
+--- com.launchdarkly:launchdarkly-android-client-sdk:5.0.0
|    +--- com.google.code.gson:gson:2.8.9
|    +--- androidx.annotation:annotation:1.2.0 -> 1.9.1
|    |    \--- androidx.annotation:annotation-jvm:1.9.1
|    |         \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.1.21 (*)
|    +--- com.launchdarkly:launchdarkly-java-sdk-internal:1.0.0
|    |    +--- com.google.code.gson:gson:2.8.9
|    |    +--- com.launchdarkly:launchdarkly-java-sdk-common:2.0.0 -> 2.1.0
|    |    +--- com.launchdarkly:launchdarkly-logging:1.1.1
|    |    \--- com.squareup.okhttp3:okhttp:4.9.1 -> 5.0.0-alpha.16
|    |         \--- com.squareup.okhttp3:okhttp-android:5.0.0-alpha.16
|    |              +--- androidx.annotation:annotation:1.9.1 (*)
|    |              +--- androidx.startup:startup-runtime:1.2.0
|    |              |    +--- androidx.annotation:annotation:1.8.1 -> 1.9.1 (*)
|    |              |    \--- androidx.tracing:tracing:1.0.0
|    |              |         \--- androidx.annotation:annotation:1.1.0 -> 1.9.1 (*)
|    |              +--- com.squareup.okio:okio:3.12.0
|    |              |    \--- com.squareup.okio:okio-jvm:3.12.0
|    |              |         \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)
|    |              \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)
|    +--- com.launchdarkly:okhttp-eventsource:3.0.0
|    |    +--- com.launchdarkly:launchdarkly-logging:1.1.1
|    |    \--- com.squareup.okhttp3:okhttp:4.9.3 -> 5.0.0-alpha.16 (*)
|    +--- com.squareup.okhttp3:okhttp:4.9.2 -> 5.0.0-alpha.16 (*)
|    +--- com.jakewharton.timber:timber:5.0.1
|    |    +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.21 -> 2.1.21 (*)
|    |    \--- org.jetbrains:annotations:20.1.0 -> 23.0.0
|    +--- com.launchdarkly:launchdarkly-java-sdk-common:2.1.0
|    \--- com.launchdarkly:launchdarkly-logging:1.1.1
+--- com.squareup.retrofit2:retrofit:3.0.0
|    +--- com.squareup.okhttp3:okhttp:4.12.0 -> 5.0.0-alpha.16 (*)
|    \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)
+--- com.squareup.wire:wire-grpc-client:5.3.3
|    \--- com.squareup.wire:wire-grpc-client-jvm:5.3.3
|         +--- com.squareup.okhttp3:okhttp:5.0.0-alpha.14 -> 5.0.0-alpha.16 (*)
|         +--- com.squareup.wire:wire-runtime:5.3.3
|         |    \--- com.squareup.wire:wire-runtime-jvm:5.3.3
|         |         +--- com.squareup.okio:okio:3.9.1 -> 3.12.0 (*)
|         |         \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.21 -> 2.1.21 (*)
|         +--- com.squareup.okio:okio:3.9.1 -> 3.12.0 (*)
|         +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0
|         |    \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0
|         |         +--- org.jetbrains:annotations:23.0.0
|         |         +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0
|         |         |    +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 (c)
|         |         |    \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (c)
|         |         \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.1.21 (*)
|         \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.21 -> 2.1.21 (*)
\--- project :lib-depends-on-latest
     +--- com.squareup.okhttp3:okhttp:5.0.0-alpha.16 (*)
     \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)

swankjesse avatar Jun 29 '25 16:06 swankjesse

Is it possible some apps are depending on okhttp-android directly. If that's above the okhttp version, could it cause this?

yschimke avatar Jun 29 '25 17:06 yschimke

./gradlew app:dependencies

@yschimke I've attached a file after running this command for one of my release configurations. I just modified some of the naming but I hope that file still makes sense.

Let me know if I need to generate that output differently.

AlexanderEggers avatar Jun 30 '25 13:06 AlexanderEggers

@AlexanderEggers That all looks correct. Everything* okhttp being bumped to to 5.0.0-alpha.16

And okhttp pulling in okhttp-android

|         +--- com.launchdarkly:okhttp-eventsource:3.0.0
|         |    +--- com.launchdarkly:launchdarkly-logging:1.1.1
|         |    \--- com.squareup.okhttp3:okhttp:4.9.3 -> 5.0.0-alpha.16 (*)
...
|    |    |    +--- com.squareup.retrofit2:retrofit:3.0.0
|    |    |    |    +--- com.squareup.okhttp3:okhttp:4.12.0 -> 5.0.0-alpha.16 (*)
...
|    |    |    |    |    |    \--- com.squareup.wire:wire-grpc-client-jvm:5.3.3
|    |    |    |    |    |         +--- com.squareup.okhttp3:okhttp:5.0.0-alpha.14 -> 5.0.0-alpha.16 (*)
...
|    \--- com.squareup.okhttp3:okhttp:5.0.0-alpha.16
|         +--- com.squareup.okhttp3:okhttp-android:5.0.0-alpha.16

You have okhttp 2 - but that's an unrelated package.

|    |    |    \--- com.google.android.libraries.places:places:4.3.1
...
|    |    |         +--- com.squareup.okhttp:okhttp:2.7.2
|    |    |         |    \--- com.squareup.okio:okio:1.6.0 -> 3.13.0 (*)

yschimke avatar Jun 30 '25 14:06 yschimke

Any ideas which could still cause the issue in the release then? If everything is using the right okhttp3 version, then things should work, right?

AlexanderEggers avatar Jun 30 '25 15:06 AlexanderEggers

Nope, I wonder how to see why R8 strips something. I know you can ask why it's kept.

-whyareyoukeeping <class-spec>

but can you try with something like (I'm bad at these)

-keepclassmembers class okhttp3.OkHttpClient$Builder {
   *** getEventListenerFactory*(*);
}

yschimke avatar Jun 30 '25 16:06 yschimke

I tried that but it is still crashing in release builds with the same error.

AlexanderEggers avatar Jun 30 '25 23:06 AlexanderEggers

I’m pretty sure this is an R8 problem and not a publishing problem. The missing function is unchanged from OkHttp 4.12 through current:

$ unzip /Users/jwilson/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/4.12.0/2f4525d4a200e97e1b87449c2cd9bd2e25b7e8cd/okhttp-4.12.0.jar
$ javap  okhttp3/OkHttpClient\$Builder.class
...
  public final okhttp3.EventListener$Factory getEventListenerFactory$okhttp();
$  unzip /Users/jwilson/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp-jvm/5.0.0-SNAPSHOT/7eccf16d57a375b5fa88257c87b52dd32192f773/okhttp-jvm-5.0.0-SNAPSHOT.jar
$ javap  okhttp3/OkHttpClient\$Builder.class
...
  public final okhttp3.EventListener$Factory getEventListenerFactory$okhttp();

swankjesse avatar Jul 02 '25 17:07 swankjesse

I'm facing the issue in debug builds without R8

minyushov avatar Jul 02 '25 17:07 minyushov

If you can share a repro project, I'm sure we can fix it in a small unit of time. Before the v5.0.0 release.

But without that, I'm not sure what we can do.

yschimke avatar Jul 02 '25 18:07 yschimke