spring-projects / spring-projects/spring-ai

Align spring-ai-openai on OkHttp 5.x (okhttp-jvm) to avoid silent duplicate classes with Spring Boot 4's OpenTelemetry starter (Maven)

Open
#6,602 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
9.5k
Forks
2.9k
Avg merge
1d 7h
Merged PRs (30d)
6

Description

Expected Behavior

spring-ai-openai should depend on the OkHttp 5.x line via the Maven-visible okhttp-jvm artifact — the same choice OpenTelemetry Java made in opentelemetry-exporter-sender-okhttp — so that Maven projects combining Spring AI with OkHttp-5-based libraries resolve exactly one copy of the okhttp3.* classes:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp-jvm</artifactId>
    <version>5.3.2</version>
</dependency>

Note: depending on the root okhttp:5.x artifact instead would not work for Maven consumers. Since OkHttp 5's Kotlin-multiplatform split, the root jar is an empty redirect stub (3 metadata files, no classes) and its POM does not reference okhttp-jvm — the redirect exists only in Gradle module metadata, which Maven ignores.

Current Behavior

spring-ai-openai:2.0.0 declares com.squareup.okhttp3:okhttp:4.12.0 (compile scope). Spring Boot 4's spring-boot-starter-opentelemetry — the default observability path — brings okhttp-jvm:5.3.2 through the OTLP sender. With spring-boot-starter-parent:4.1.0, these two starters alone reproduce:

+- org.springframework.boot:spring-boot-starter-opentelemetry:jar:4.1.0:compile
|  \- io.opentelemetry:opentelemetry-exporter-otlp:jar:1.62.0:runtime
|     \- io.opentelemetry:opentelemetry-exporter-sender-okhttp:jar:1.62.0:runtime
|        \- com.squareup.okhttp3:okhttp-jvm:jar:5.3.2:runtime
\- org.springframework.ai:spring-ai-starter-model-openai:jar:2.0.0:compile
   \- org.springframework.ai:spring-ai-openai:jar:2.0.0:compile
      \- com.squareup.okhttp3:okhttp:jar:4.12.0:compile

Because the artifactIds differ, Maven's version mediation never sees a conflict: both jars land on the runtime classpath with 253 class files duplicated between them (essentially all of okhttp3.*). Maven and Boot's repackaging emit no warning — Gradle fails loudly on this exact artifact pair (see open-telemetry/opentelemetry-android#1294).

Which bytecode actually runs is then decided by classpath order. In our Boot fat jar, okhttp-jvm-5.3.2.jar precedes okhttp-4.12.0.jar, so the OpenAI client already runs on OkHttp 5 classes today — silently, and dependent on nothing more than dependency declaration order. Mixed 4.x/5.x-jvm classpaths are known to produce hard failures such as NoSuchMethodError when the order or API surface shifts (e.g. aws/aws-sdk-kotlin#983).

This can't be cleanly fixed from the consumer side: mediation can't converge two artifactIds, Spring Boot no longer manages OkHttp versions at all (spring-projects/spring-boot#36632), and pinning root okhttp to 5.x just resolves to the empty stub jar described above.

Context

  • Spring AI 2.0.0, Spring Boot 4.1.0, Java 25, Maven 3.9.9.
  • We combine spring-ai-starter-model-openai and spring-ai-starter-mcp-server-webmvc with spring-boot-starter-opentelemetry. Since the OTel starter is Boot 4's standard observability setup, we expect this pairing to be common among Maven-based Spring AI applications.
  • Impact on us: our dependency-hygiene tooling flags the 253 shadowed classes, and the OpenAI client effectively runs on an OkHttp version other than the one Spring AI declares and presumably tests against.
  • Workaround we applied — exclude the 4.x jar and let the client run on okhttp-jvm:5.3.2 (which classpath order was already doing; OkHttp 5 retains the 4.x public API, and the client works unmodified):
<exclusion>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
</exclusion>

This is fragile: the OpenAI client's HTTP classes now arrive only via the OTel starter's runtime dependency, so removing that starter would cause NoClassDefFoundError.

  • Alternative considered: swapping the OTLP sender to opentelemetry-exporter-sender-jdk, which removes OkHttp 5 but changes the telemetry transport and keeps Spring AI on the maintenance-only 4.x line.
  • Related issues (searched first): #5838 proposes replacing OkHttp with JDK HttpClient in the OpenAI SDK integration, which would resolve this more fundamentally — this request is the narrower dependency alignment until/unless that lands. #6318 and #354 show OkHttp on the client's hot path.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the Maven dependency declaration for the spring-ai-openai artifact and compare it with the okhttp-jvm dependency used by opentelemetry-exporter-sender-okhttp. Verify the published dependency tree with the Spring Boot OpenTelemetry combination; done means the OpenAI integration resolves okhttp-jvm without also bringing the root okhttp 4.12.0 artifact.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
build-system
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.