{"record":{"id":"f959919a1aa45a0b","repo":"apache/cassandra","slug":"you-shouldn-t-wrap-the-dynamicendpointsnitch-with","errorCode":null,"errorMessage":"You shouldn't wrap the DynamicEndpointSnitch (within itself or otherwise)","messagePattern":"You shouldn't wrap the DynamicEndpointSnitch \\(within itself or otherwise\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/locator/DynamicEndpointSnitch.java","lineNumber":250,"sourceCode":"        if (scored2 == null)\n        {\n            scored2 = defaultStore(a2.endpoint());\n        }\n\n        if (scored1.equals(scored2))\n            return subCompare.compare(a1, a2);\n        if (scored1 < scored2)\n            return -1;\n        else\n            return 1;\n    }\n\n    public int compareEndpoints(InetAddressAndPort target, Replica a1, Replica a2)\n    {\n        // That function is fundamentally unsafe because the scores can change at any time and so the result of that\n        // method is not stable for identical arguments. This is why we don't rely on super.sortByProximity() in\n        // sortByProximityWithScore().\n        throw new UnsupportedOperationException(\"You shouldn't wrap the DynamicEndpointSnitch (within itself or otherwise)\");\n    }\n\n    public void receiveTiming(InetAddressAndPort host, long latency, TimeUnit unit) // this is cheap\n    {\n        ExponentiallyDecayingReservoir sample = samples.get(host);\n        if (sample == null)\n        {\n            ExponentiallyDecayingReservoir maybeNewSample = new ExponentiallyDecayingReservoir(WINDOW_SIZE, ALPHA);\n            sample = samples.putIfAbsent(host, maybeNewSample);\n            if (sample == null)\n                sample = maybeNewSample;\n        }\n        sample.update(unit.toMillis(latency));\n    }\n\n    @VisibleForTesting\n    public void updateScores() // this is expensive\n    {","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/locator/DynamicEndpointSnitch.java#L232-L268","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (cassandra.yaml)\nendpoint_snitch: DynamicEndpointSnitch\n// after\nendpoint_snitch: GossipingPropertyFileSnitch\ndynamic_snitch_update_interval_in_ms: 100","handlingStrategy":"type-guard","validationCode":"IEndpointSnitch snitch = DatabaseDescriptor.getEndpointSnitch();\nif (snitch instanceof DynamicEndpointSnitch) throw new IllegalStateException(\"Do not use DES comparator directly\");","typeGuard":"boolean isDes(IEndpointSnitch s) { return s instanceof DynamicEndpointSnitch; }","tryCatchPattern":"try { snitch.compareEndpoints(target, a1, a2); }\ncatch (UnsupportedOperationException e) { /* use sortByProximity instead */ }","preventionTips":["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"],"tags":["snitch","unsupported-operation","configuration","routing"],"backgroundTag":"unsupported-operation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}