{"record":{"id":"f05b2df3f97a6a17","repo":"apache/cassandra","slug":"new-tokens-exceed-total-bounds-of-current-placemen","errorCode":null,"errorMessage":"New tokens exceed total bounds of current placement ranges ","messagePattern":"New tokens exceed total bounds of current placement ranges ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/ownership/ReplicaGroups.java","lineNumber":317,"sourceCode":"    {\n        return new Builder(expectedSize);\n    }\n\n    @VisibleForTesting\n    public static ReplicaGroups splitRangesForPlacement(List<Token> tokens, ReplicaGroups placement)\n    {\n        if (placement.ranges.isEmpty())\n            return placement;\n\n        Builder newPlacement = ReplicaGroups.builder();\n        List<VersionedEndpoints.ForRange> eprs = new ArrayList<>(placement.endpoints);\n        eprs.sort(Comparator.comparing(a -> a.range().left));\n        Token min = eprs.get(0).range().left;\n        Token max = eprs.get(eprs.size() - 1).range().right;\n\n        // if any token is < the start or > the end of the ranges covered, error\n        if (tokens.get(0).compareTo(min) < 0 || (!max.equals(min) && tokens.get(tokens.size()-1).compareTo(max) > 0))\n            throw new IllegalArgumentException(\"New tokens exceed total bounds of current placement ranges \" + tokens + \" \" + eprs);\n        Iterator<VersionedEndpoints.ForRange> iter = eprs.iterator();\n        VersionedEndpoints.ForRange current = iter.next();\n        for (Token token : tokens)\n        {\n            // handle special case where one of the tokens is the min value\n            if (token.equals(min))\n                continue;\n\n            assert current != null : tokens + \" \" + eprs;\n            Range<Token> r = current.get().range();\n            int cmp = token.compareTo(r.right);\n            if (cmp == 0)\n            {\n                newPlacement.withReplicaGroup(current);\n                if (iter.hasNext())\n                    current = iter.next();\n                else\n                    current = null;","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/ownership/ReplicaGroups.java#L299-L335","documentation":"splitRangesForPlacement splits existing placement ranges so new tokens become range boundaries. Before splitting it validates that the proposed tokens fit within the total bounds [min, max] of the current placement ranges; IllegalArgumentException is thrown when any token falls outside those bounds, since no existing range could be split to cover it.","triggerScenarios":"Calling the TCM bootstrap/replace/move placement APIs (which route through splitRangesForPlacement) with a token set whose minimum is below the left boundary or whose maximum is above the right boundary of the current canonical placements.","commonSituations":"Assigning a new token outside the currently allocated token space (e.g. wrong partitioner ring bounds); attempting a multi-token bootstrap where one token was accidentally mistyped; replaying placement deltas against ranges that were never allocated (empty or partial ring).","solutions":["Verify every proposed token lies within the current placement range bounds before calling the API (tokens.get(0) >= min and tokens.last <= max)","Re-assign tokens using the same partitioner/random token allocator that produced the existing ring","If the ring is intentionally being extended, first allocate initial ranges covering the new tokens (initialize as a new datacenter/cluster operation) rather than splitting","Correct the token configuration (initial_token / bootstrap token list) and retry the operation"],"exampleFix":"// before\ncluster.bootstrap(toBootstrap.stream().map(TokenUtils::getToken).collect(Collectors.toSet()));\n// after\nSortedSet<Token> sorted = ...;\nToken min = placements.first().range().left, max = placements.last().range().right;\nif (sorted.first().compareTo(min) < 0 || sorted.last().compareTo(max) > 0)\n    throw new IllegalArgumentException(\"token outside current placement bounds\");\ncluster.bootstrap(sorted);","handlingStrategy":"validation","validationCode":"Token min = eprs.get(0).range().left, max = eprs.get(eprs.size()-1).range().right;\nif (tokens.first().compareTo(min) < 0 || tokens.last().compareTo(max) > 0)\n    throw new IllegalArgumentException(\"proposed tokens outside current placement bounds\");","typeGuard":null,"tryCatchPattern":"try { splitRangesForPlacement(tokens, eprs, epoch); } catch (IllegalArgumentException e) { /* regenerate tokens with the cluster's partitioner */ }","preventionTips":["Generate new tokens with the same partitioner as the existing ring","Sanity-check token ordering and bounds before bootstrap/replace operations","Never hand-edit token lists; use the cluster's token allocator"],"tags":["tcm","token-management","bootstrap","range-splitting","illegal-argument"],"backgroundTag":"value-out-of-range","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"}