apache/cassandra · error · UnsupportedOperationException
You shouldn't wrap the DynamicEndpointSnitch (within itself…
Error message
You shouldn't wrap the DynamicEndpointSnitch (within itself or otherwise)
What it means
DynamicEndpointSnitch (DES) overrides compareEndpoints to deliberately throw UnsupportedOperationException. Its latency scores change constantly, so a comparator over DES would be non-deterministic; wrapping DES inside another snitch (including itself) is unsafe and unsupported, so any comparison call throws.
Solutions
- Remove DynamicEndpointSnitch from the snitch wrapper chain — configure the base snitch (e.g. GossipingPropertyFileSnitch) as endpoint_snitch and let dynamic_snitch_options wrap it automatically
- Never pass a DES instance as the delegate of another snitch
- Use sortByProximityWithScore or the ranking APIs instead of calling compareEndpoints directly in custom code
- Upgrade config: in modern Cassandra DES is implicit via dynamic_snitch options; delete explicit DES configuration
Example fix
// before (cassandra.yaml) endpoint_snitch: DynamicEndpointSnitch // after endpoint_snitch: GossipingPropertyFileSnitch dynamic_snitch_update_interval_in_ms: 100
Defensive patterns
Strategy: type-guard
Validate before calling
IEndpointSnitch snitch = DatabaseDescriptor.getEndpointSnitch();
if (snitch instanceof DynamicEndpointSnitch) throw new IllegalStateException("Do not use DES comparator directly"); Type guard
boolean isDes(IEndpointSnitch s) { return s instanceof DynamicEndpointSnitch; } Try / catch
try { snitch.compareEndpoints(target, a1, a2); }
catch (UnsupportedOperationException e) { /* use sortByProximity instead */ } Prevention
- Never nest DynamicEndpointSnitch in snitch delegation chains
- Rely on dynamic_snitch_options rather than wrapping DES explicitly
- Treat DES as an internal wrapper, not a public comparator API
When it happens
Trigger: Calling compareEndpoints (or sortByProximity paths that fall back to it) on a snitch instance that is a DynamicEndpointSnitch — which happens only if DES was configured as a delegate/wrapper of another snitch or vice versa.
Common situations: cassandra.yaml misconfigured so endpoint_snitch or the snitch wrapper chain nests DynamicEndpointSnitch (e.g. dynamic_snitch combined incorrectly with a delegated snitch); custom code calling sortByProximity directly on a DES reference.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Configuration must specify either node_proximity and…
- DC or rack not found in snitch properties, check your…
- IEndpointSnitch has been deprecated and is no longer in use
- Initial location provider rejected registration location…
- is deprecated and not actively maintained. It will be…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/f959919a1aa45a0b.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/locator/DynamicEndpointSnitch.java:250
if (scored2 == null)
{
scored2 = defaultStore(a2.endpoint());
}
if (scored1.equals(scored2))
return subCompare.compare(a1, a2);
if (scored1 < scored2)
return -1;
else
return 1;
}
public int compareEndpoints(InetAddressAndPort target, Replica a1, Replica a2)
{
// That function is fundamentally unsafe because the scores can change at any time and so the result of that
// method is not stable for identical arguments. This is why we don't rely on super.sortByProximity() in
// sortByProximityWithScore().
throw new UnsupportedOperationException("You shouldn't wrap the DynamicEndpointSnitch (within itself or otherwise)");
}
public void receiveTiming(InetAddressAndPort host, long latency, TimeUnit unit) // this is cheap
{
ExponentiallyDecayingReservoir sample = samples.get(host);
if (sample == null)
{
ExponentiallyDecayingReservoir maybeNewSample = new ExponentiallyDecayingReservoir(WINDOW_SIZE, ALPHA);
sample = samples.putIfAbsent(host, maybeNewSample);
if (sample == null)
sample = maybeNewSample;
}
sample.update(unit.toMillis(latency));
}
@VisibleForTesting
public void updateScores() // this is expensive
{View on GitHub (pinned to 88fd0f6a0e)