{"record":{"id":"6ec5656b6dcb65ad","repo":"apache/cassandra","slug":"no-group-found-for-range-of-supplied-replica-s","errorCode":null,"errorMessage":"No group found for range of supplied replica %s (%s)","messagePattern":"No group found for range of supplied replica (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/ownership/ReplicaGroups.java","lineNumber":414,"sourceCode":"                                                   EndpointsForRange old = v.get();\n                                                   return VersionedEndpoints.forRange(epoch,\n                                                                                      old.newBuilder(old.size() + 1)\n                                                                                         .addAll(old)\n                                                                                         .add(replica, ReplicaCollection.Builder.Conflict.NONE)\n                                                                                         .build());\n                                               });\n;            if (group == null)\n                replicaGroups.put(replica.range(), VersionedEndpoints.forRange(epoch, EndpointsForRange.of(replica)));\n            return this;\n\n        }\n\n        public Builder withoutReplica(Epoch epoch, Replica replica)\n        {\n            Range<Token> range = replica.range();\n            VersionedEndpoints.ForRange group = replicaGroups.get(range);\n            if (group == null)\n                throw new IllegalArgumentException(String.format(\"No group found for range of supplied replica %s (%s)\",\n                                                                 replica, range));\n            EndpointsForRange without = group.get().without(Collections.singleton(replica.endpoint()));\n            if (without.isEmpty())\n                replicaGroups.remove(range);\n            else\n                replicaGroups.put(range, VersionedEndpoints.forRange(epoch, without));\n            return this;\n        }\n\n        public Builder withReplicaGroup(VersionedEndpoints.ForRange replicas)\n        {\n            VersionedEndpoints.ForRange group =\n                replicaGroups.computeIfPresent(replicas.range(),\n                                               (t, v) -> {\n                                                   EndpointsForRange old = v.get();\n                                                   return VersionedEndpoints.forRange(Epoch.max(v.lastModified(), replicas.lastModified()),\n                                                                                      combine(old, replicas.get()));\n                                               });","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/ownership/ReplicaGroups.java#L396-L432","documentation":"ReplicaGroups.Builder.withoutReplica removes a single replica from the placement group owning its range. It throws IllegalArgumentException when no group in the current replicaGroups map matches the replica's exact range, i.e. the caller asked to remove a replica from a range this builder does not track.","triggerScenarios":"Calling withoutReplica(epoch, replica) with a replica whose Range<Token> is not a key in the builder's replicaGroups map — typically when computing a placement delta (e.g. during decommission or range movement) using a replica taken from a different/stale placements snapshot.","commonSituations":"A decommission or move operation was partially applied so the range in the builder differs from the replica's range; passing replicas from a canonical placement into a builder seeded from the pending placement; concurrent metadata transformations changed the ranges between reads.","solutions":["Re-read the current placements from ClusterMetadata and rebuild the Builder so the replica's range matches an existing group","Confirm the operation is idempotent/retryable: if the range group is already gone the removal may have been applied; skip instead of throwing","Ensure the replica object passed to withoutReplica comes from the same snapshot the Builder was created from (same epoch)","Re-run the placement transformation from a fresh metadata read"],"exampleFix":"// before\nbuilder.withoutReplica(epoch, replica);\n// after\nVersionedEndpoints.ForRange group = replicaGroups.get(replica.range());\nif (group != null)\n    builder.withoutReplica(epoch, replica);","handlingStrategy":"try-catch","validationCode":"VersionedEndpoints.ForRange group = builderReplicaGroups.get(replica.range());\nif (group == null || !group.get().contains(replica.endpoint()))\n    throw new IllegalArgumentException(\"builder lacks replica: \" + replica);","typeGuard":null,"tryCatchPattern":"try { builder.withoutReplica(epoch, replica); } catch (IllegalArgumentException e) { /* skip: removal already applied or rebuild from fresh metadata */ }","preventionTips":["Always build the Builder and source replicas from the same metadata epoch/snapshot","Make removal operations idempotent: treat missing ranges as already-applied","Rebuild builders after any concurrent metadata transformation"],"tags":["tcm","placement","range-mismatch","illegal-argument"],"backgroundTag":"resource-not-found","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"}