DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
Status
Current state: Withdrawn
Withdrawn reason: The Jetty team has reverted all SLF4J 2.x fluent API usage across 12.0.x (#14642), 12.1.x (#14748), and indicated 13.0.x will also stay on non-fluent APIs (#14747). Kafka can upgrade Jetty directly once 12.0.34 is released, resolving the blocked CVEs without shadowing.
Discussion thread: https://lists.apache.org/thread/o4v30n8lrhj6wbhz1qoz0qglw5998tgm
JIRA: KAFKA-20216 - Getting issue details... STATUS
Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast).
Motivation
Kafka upgraded from Jetty 9 to Jetty 12 in Kafka 4.0 via KIP-1013. Although Jetty 12 has declared a dependency on slf4j-api 2.x since its initial release, Kafka excludes the transitive slf4j-api and uses its own SLF4J 1.7.x instead. This worked at the time because early Jetty 12 versions only called SLF4J API methods that exist in both 1.x and 2.x.
However, starting from Jetty 12.0.30, Jetty's production code began using SLF4J 2.x-specific fluent API calls (e.g., Logger.atDebug()), which do not exist in SLF4J 1.7.x. This causes NoSuchMethodError at runtime. This incompatibility was discovered during KAFKA-20168, when an attempt to upgrade Jetty for CVE-2025-5115 revealed the SLF4J conflict. As a workaround, Kafka is currently pinned to Jetty 12.0.25, the version chosen during that CVE fix.
This version pin at 12.0.25 creates a maintenance burden: any future Jetty security patch (CVE) that ships only in versions ≥ 12.0.30 cannot be adopted without resolving the SLF4J conflict. This is not a hypothetical risk — there are already two unresolved CVEs blocked by this issue:
- KAFKA-20270 — CVE-2026-1605 (jetty-server), fixed in Jetty ≥ 12.0.32
- KAFKA-20283 — CVE-2025-11143 (jetty-http), fixed in Jetty ≥ 12.0.31
Upgrading Kafka's own SLF4J from 1.x to 2.x is not viable in the 4.x release line because:
- Breaking change for downstream users: Kafka's client libraries (
kafka-clients, Kafka Streams) are used as Maven/Gradle dependencies by many applications. Upgradingslf4j-apito 2.x would pull the new version into those applications transitively. SLF4J 2.x changes the provider discovery mechanism fromStaticLoggerBindertoServiceLoader, so any application that uses a SLF4J 1.x provider (e.g.,log4j-slf4j-impl,logback-classic1.2.x) would get runtime errors or silent logging loss. Those users would be forced to upgrade their logging backend to SLF4J 2.x-compatible versions (e.g.,log4j-slf4j2-impl,logback-classic1.4+). - KIP-1064: A full SLF4J 2.x upgrade has been discussed in KIP-1064, but the discussion concluded that the scope of breaking changes is too large for the 4.x release line, and the community prefers to wait and see how the logging landscape evolves before committing to SLF4J 2 or an alternative. We cannot rely on KIP-1064 to solve the immediate Jetty compatibility problem.
We need a targeted solution that allows Jetty to use SLF4J 2.x internally while Kafka continues to use SLF4J 1.x, without affecting any public interfaces.
Public Interfaces
This KIP does not change any public interfaces. The changes are purely internal dependency management:
- No changes to Kafka's public API, configuration, wire protocol, or command-line tools.
- No changes to the logging behavior visible to users.
- The Jetty classes remain accessible to Connect plugins through the same package names (
org.eclipse.jetty.*).
Proposed Changes
Create a new internal Gradle module (connect:jetty-shadow) that uses the Gradle Shadow plugin to bundle Jetty, slf4j-api 2.x, and log4j-slf4j2-impl into a single JAR with the following relocation rules:
org.slf4j→org.apache.kafka.shaded.org.slf4jorg.apache.logging.slf4j→org.apache.kafka.shaded.org.apache.logging.slf4j
This rewrites all SLF4J references inside the Jetty bytecode so they no longer conflict with Kafka's own slf4j-api 1.x. The shadow JAR also includes log4j-slf4j2-impl (relocated), which bridges the relocated SLF4J 2.x calls to the Log4j2 core already on Kafka's classpath, so Jetty's log output continues to appear alongside Kafka's own logs.
The Connect modules (connect:runtime, connect:mirror) depend on connect:jetty-shadow instead of the individual Jetty artifacts. The trogdor module benefits from this change transitively via its existing dependency on connect:runtime. The exclude group: 'org.slf4j' workaround is no longer needed.
Once the shadowing is in place, the Jetty version pin at 12.0.25 can be removed and Jetty can be upgraded to the latest 12.0.x version.
Kafka's own SLF4J version remains at 1.7.x. Jetty's public class names (org.eclipse.jetty.*) are not relocated — Kafka source code continues to import and use them directly. No changes to Kafka Connect's plugin classpath isolation or REST API behavior. If Kafka upgrades to SLF4J 2.x in a future major release, the shadow module can simply be removed: (1) Jetty classes are not relocated in the shadow JAR — they remain at org.eclipse.jetty.* — so removing the module does not change any class paths or require recompilation of user code or plugins; (2) with Kafka on SLF4J 2.x, Jetty and Kafka share the same SLF4J version natively, so the version conflict that motivated shadowing no longer exists and Gradle's normal version resolution is sufficient. SLF4J 2.x is backward compatible at the API level, so connector plugins compiled against SLF4J 1.x continue to work without recompilation.
Compatibility, Deprecation, and Migration Plan
- User impact: None. This is a transparent internal change. Users do not interact with Jetty or SLF4J through Kafka's public API.
- Connect plugin compatibility: Connect plugins that depend on Jetty classes from the worker classpath will continue to work, as Jetty packages are not relocated.
- Binary compatibility: The shaded JAR is an implementation detail. No public artifacts change their dependency coordinates.
- Logging with alternative backends: If a user has replaced Log4j2 with an alternative logging backend (e.g., Logback), Jetty's logs will be silently lost under the shadow module because the relocated
log4j-slf4j2-implbridge cannot findlog4j-apion the classpath. This is a regression compared to the current behavior where Jetty's logs follow the user's chosen backend via SLF4J 1.x. However, this only affects users who have both (1) removed Log4j2 from the classpath and (2) need to inspect Jetty-level logs for debugging. The REST server's functional behavior is not affected. This limitation is resolved once the shadow module is removed after KIP-1064. - Migration: No user migration is required.
Test Plan
- All existing unit and integration tests for Connect REST servers must pass without modification.
- Verify that upgrading Jetty to ≥ 12.0.30 no longer causes
NoSuchMethodErrorat runtime.
Rejected Alternatives
Upgrade Kafka to SLF4J 2.x (KIP-1064): As discussed in KIP-1064, upgrading SLF4J is a breaking change that affects all Kafka users and their logging backends. It should be done as part of a major release (Kafka 5.0). The current proposal solves the immediate Jetty compatibility problem without imposing any user-facing changes, and it does not conflict with a future SLF4J 2.x upgrade — at that point, the shadow module can simply be removed as described in Proposed Changes.
Wait for Jetty to remove SLF4J 2.x fluent API: The Jetty team has opened an issue to remove SLF4J fluent API usage from the 12.0.x branch, but a Jetty maintainer has described this as a temporary workaround: "Jetty 12.1.x is already using the fluent API much more extensively and there is no plan to go back." Relying on upstream to avoid SLF4J 2.x is not a sustainable long-term strategy.
Update (2026-03-29): The Jetty team has since reverted all SLF4J 2.x fluent API usage across all branches — 12.0.x (#14642), 12.1.x (#14748), and plans to keep 13.0.x on non-fluent APIs as well (#14747). This alternative is now the accepted path forward, making the shadow approach unnecessary. This KIP has been withdrawn.