Skip to content

Fix analytics ServiceConfigurationError on IDEs that bundle their own ktor (2025.2+/2026.1)#174

Merged
Pushpavel merged 1 commit into
Pushpavel:mainfrom
znzryb:fix-ktor-engine-classloader-clash
Jul 12, 2026
Merged

Fix analytics ServiceConfigurationError on IDEs that bundle their own ktor (2025.2+/2026.1)#174
Pushpavel merged 1 commit into
Pushpavel:mainfrom
znzryb:fix-ktor-engine-classloader-clash

Conversation

@znzryb

@znzryb znzryb commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Motivation

On recent IDEs (2025.2+ — observed on RustRover and CLion 2026.1.4) every gathered problem batch pops an IDE internal error from AutoCp:

java.util.ServiceConfigurationError: io.ktor.client.HttpClientEngineContainer: io.ktor.client.engine.cio.CIOEngineContainer not a subtype (full stack trace)
java.util.ServiceConfigurationError: io.ktor.client.HttpClientEngineContainer: io.ktor.client.engine.cio.CIOEngineContainer not a subtype
    at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:559)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1115)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1142)
    at java.base/java.util.ServiceLoader$1.hasNext(ServiceLoader.java:1164)
    at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1246)
    at kotlin.collections.CollectionsKt___CollectionsKt.toCollection(_Collections.kt:1303)
    at kotlin.collections.CollectionsKt___CollectionsKt.toMutableList(_Collections.kt:1336)
    at kotlin.collections.CollectionsKt___CollectionsKt.toList(_Collections.kt:1327)
    at io.ktor.client.HttpClientJvmKt.<clinit>(HttpClientJvm.kt:39)
    at com.github.pushpavel.autocp.common.analytics.GoogleAnalytics.<init>(GoogleAnalytics.kt:24)
    at com.github.pushpavel.autocp.common.analytics.GoogleAnalytics.<clinit>(GoogleAnalytics.kt:62)
    at com.github.pushpavel.autocp.common.analytics.listeners.ProblemGatherListener.onGenerated(ProblemGatherListener.kt:14)
    at com.intellij.util.messages.impl.MessageBusImplKt.invokeMethod(MessageBusImpl.kt:831)
    at com.intellij.util.messages.impl.MessageBusImplKt.invokeListener(MessageBusImpl.kt:775)
    at com.intellij.util.messages.impl.MessageBusImplKt.deliverMessage(MessageBusImpl.kt:514)
    at com.intellij.util.messages.impl.MessageBusImplKt.pumpWaiting(MessageBusImpl.kt:493)
    at com.intellij.util.messages.impl.MessageBusImplKt.access$pumpWaiting(MessageBusImpl.kt:1)
    at com.intellij.util.messages.impl.MessagePublisher.invoke(MessageBusImpl.kt:556)
    at jdk.proxy11/jdk.proxy11.$Proxy244.onGenerated(Unknown Source)
    at com.github.pushpavel.autocp.gather.base.ProblemGatheringPipeline.flushProblemQueue$lambda$2(ProblemGatheringPipeline.kt:96)
    at com.intellij.openapi.project.DumbServiceImpl.smartInvokeLater$lambda$0(DumbServiceImpl.kt:728)
    at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:236)
    at com.intellij.openapi.application.TransactionGuardImpl.access$100(TransactionGuardImpl.java:22)
    at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:198)
    at com.intellij.openapi.application.impl.AppImplKt$runnableUnitFunction$1.invoke(appImpl.kt:124)
    at com.intellij.openapi.application.impl.AppImplKt$runnableUnitFunction$1.invoke(appImpl.kt:124)
    at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.runWriteIntentReadAction(NestedLocksThreadingSupport.kt:705)
    at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:1094)
    at com.intellij.openapi.application.impl.ApplicationImpl$7.lambda$run$0(ApplicationImpl.java:648)
    at com.intellij.concurrency.ThreadContext.installThreadContext(threadContext.kt:305)
    at com.intellij.openapi.application.impl.ApplicationImpl$7.run(ApplicationImpl.java:646)
    at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:192)
    at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:192)
    at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:198)
    at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:192)
    at com.intellij.util.concurrency.ContextRunnable.lambda$run$0(ContextRunnable.java:26)
    at com.intellij.concurrency.ThreadContext.resetThreadContext(threadContext.kt:294)
    at com.intellij.util.concurrency.ContextRunnable.run(ContextRunnable.java:25)
    at com.intellij.openapi.application.impl.NonBlockingFlushQueue.runNextEvent$lambda$1$1$0(NonBlockingFlushQueue.kt:334)
    at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:928)
    at com.intellij.openapi.application.impl.NonBlockingFlushQueue.runNextEvent$lambda$1$1(NonBlockingFlushQueue.kt:333)
    at com.intellij.concurrency.ThreadContext.resetThreadContext(threadContext.kt:294)
    at com.intellij.openapi.application.impl.NonBlockingFlushQueue.runNextEvent$lambda$1(NonBlockingFlushQueue.kt:330)
    at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.tryRunWriteIntentReadAction(NestedLocksThreadingSupport.kt:747)
    at com.intellij.openapi.application.impl.NonBlockingFlushQueue.runNextEvent(NonBlockingFlushQueue.kt:326)
    at com.intellij.openapi.application.impl.NonBlockingFlushQueue.flushNow(NonBlockingFlushQueue.kt:305)
    at com.intellij.openapi.application.impl.NonBlockingFlushQueue.FLUSH_NOW$lambda$0(NonBlockingFlushQueue.kt:167)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:323)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:732)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:711)
    at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:721)
    at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:574)
    at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$0$0$0(IdeEventQueue.kt:378)
    at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$0(IdeEventQueue.kt:1111)
    at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:106)
    at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:1111)
    at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$0(IdeEventQueue.kt:376)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:416)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

Root cause

Those IDE builds ship their own ktor in the platform classpath (lib/intellij.libraries.ktor.client.cio.jar etc). GoogleAnalytics creates its client as HttpClient { ... } with no engine named, so ktor falls back to engine auto-discovery via java.util.ServiceLoader. The plugin classloader's resource lookup also sees the platform's META-INF/services/io.ktor.client.HttpClientEngineContainer, and loading the CIOEngineContainer it names yields a class that implements the platform copy of HttpClientEngineContainer — not the one from the ktor 2.1.2 the plugin bundles. ServiceLoader iteration then throws not a subtype, client construction fails, and since it happens inside the problem-gathering message-bus listener the exception surfaces as an IDE internal error. Older IDEs don't bundle ktor, which is why this never showed up before.

Fix

  • Name the bundled engine explicitly — HttpClient(Java) { ... } (ktor-client-java is already a dependency) — so no service discovery happens at all.
  • Belt and braces: create the client lazily and wrap the send in runCatching. Analytics is best-effort; whatever else goes wrong in it should never pop an IDE error over the user's workflow.

Testing

  • compileKotlin passes.
  • HttpClient(Java) takes the explicit-factory constructor path, which never touches ServiceLoader (HttpClientJvm.kt's engine list is only consulted by the no-arg overload), so the failing lookup in the trace above is no longer reachable.

On 2025.2+ IDEs (RustRover, CLion 2026.1, ...) the platform ships its
own ktor in lib/ (intellij.libraries.ktor.client.cio.jar). Creating the
analytics HttpClient without naming an engine makes ktor discover one
through java.util.ServiceLoader, and the plugin classloader's resource
lookup also sees the platform's service file: it then tries to load the
platform's CIOEngineContainer, which implements the platform copy of
HttpClientEngineContainer rather than the one bundled with the plugin,
and client construction dies with

  java.util.ServiceConfigurationError:
  io.ktor.client.HttpClientEngineContainer:
  io.ktor.client.engine.cio.CIOEngineContainer not a subtype

Since GoogleAnalytics fires from the problem-gathering message bus
listener, every gathered batch popped an IDE internal error on those
IDEs.

Name the bundled Java engine explicitly — HttpClient(Java) — so no
service discovery happens at all. Also create the client lazily and
wrap the send in runCatching: analytics is best-effort and must never
surface an IDE error, whatever else goes wrong.
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 0% with 23 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...shpavel/autocp/common/analytics/GoogleAnalytics.kt 0.00% 23 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Files with missing lines Coverage Δ
...shpavel/autocp/common/analytics/GoogleAnalytics.kt 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Pushpavel
Pushpavel merged commit e2cfcc0 into Pushpavel:main Jul 12, 2026
4 checks passed
Pushpavel added a commit that referenced this pull request Jul 12, 2026
…wser extension

- feat: submit support via companion browser extension (#172)
- fix: no longer crowd out native run configurations (#173)
- fix: analytics ServiceConfigurationError on 2025.2+ IDEs bundling ktor (#174)
- fix: endless loading of Project settings page with no project open (#175)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants