-
Notifications
You must be signed in to change notification settings - Fork 38
Description
Bug Report
Version
com.scylladb:java-driver-core:4.19.0.5
Description
Starting with version 4.19.0.5, DefaultLoadBalancingPolicy.moveReplicasToFront() uses org.apache.commons.lang3.tuple.Pair, but commons-lang3 is not declared as a dependency in core/pom.xml (or the parent POM). This causes a NoClassDefFoundError / ClassNotFoundException at runtime when the load balancing policy attempts to build a query plan for regular (non-LWT) requests on multi-node clusters.
Root Cause
PR #784 ("Fix: LWT routing enhancements to utilize LBP"), merged on 2026-01-27, refactored DefaultLoadBalancingPolicy to return Pair<Integer, Integer> from the moveReplicasToFront method:
import org.apache.commons.lang3.tuple.Pair;
// ...
private Pair<Integer, Integer> moveReplicasToFront(Object[] currentNodes, List<Node> allReplicas) {
// ...
return Pair.of(replicaCount, localRackReplicaCount);
}However, the corresponding org.apache.commons:commons-lang3 dependency was never added to core/pom.xml or the parent pom.xml.
Why this is not caught during testing
The failure only occurs in multi-node production clusters where DefaultLoadBalancingPolicy.newQueryPlanRegular() is invoked and replicas are non-empty. Single-node integration tests don't exercise the moveReplicasToFront code path because there are no replicas to move, so the Pair class is never loaded.
Stack Trace
java.lang.NoClassDefFoundError: org/apache/commons/lang3/tuple/Pair
at com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy.moveReplicasToFront(DefaultLoadBalancingPolicy.java:268)
at com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy.newQueryPlanRegular(DefaultLoadBalancingPolicy.java:205)
at com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy.newQueryPlan(DefaultLoadBalancingPolicy.java:175)
at com.datastax.oss.driver.internal.core.metadata.LoadBalancingPolicyWrapper.newQueryPlan(LoadBalancingPolicyWrapper.java:159)
at com.datastax.oss.driver.internal.core.cql.CqlRequestHandler.onThrottleReady(CqlRequestHandler.java:213)
at com.datastax.oss.driver.internal.core.session.throttling.PassThroughRequestThrottler.register(PassThroughRequestThrottler.java:54)
at com.datastax.oss.driver.internal.core.cql.CqlRequestHandler.<init>(CqlRequestHandler.java:191)
at com.datastax.oss.driver.internal.core.cql.CqlRequestAsyncProcessor.process(CqlRequestAsyncProcessor.java:46)
at com.datastax.oss.driver.internal.core.cql.CqlRequestAsyncProcessor.process(CqlRequestAsyncProcessor.java:31)
at com.datastax.oss.driver.internal.core.session.DefaultSession.execute(DefaultSession.java:241)
...
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.tuple.Pair
... 38 common frames omitted
Suggested Fix
Either:
- Add
commons-lang3as a runtime dependency incore/pom.xml:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.17.0</version>
</dependency>- Or replace the usage with a simple two-element return type (e.g., an
int[]or a private inner record/class) to avoid pulling in an extra transitive dependency for a single usage.
Workaround
Users can add commons-lang3 explicitly to their own project dependencies:
Maven:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.17.0</version>
</dependency>sbt:
libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.17.0"Environment
- ScyllaDB Java Driver:
4.19.0.5 - Java: 17+
- Multi-node ScyllaDB cluster (not reproducible with single-node test setups)