{"record":{"id":"e2b2dd77095b190b","repo":"apache/cassandra","slug":"unexpected-string-tokenscanner-next","errorCode":null,"errorMessage":"Unexpected string: ${tokenScanner.next()}","messagePattern":"Unexpected string: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/Rebuild.java","lineNumber":206,"sourceCode":"\n\n    private static RangesAtEndpoint rangesForRebuildWithTokens(String tokens, String keyspace)\n    {\n        Token.TokenFactory factory = StorageService.instance.getTokenFactory();\n        List<Range<Token>> ranges = new ArrayList<>();\n        Pattern rangePattern = Pattern.compile(\"\\\\(\\\\s*(-?\\\\w+)\\\\s*,\\\\s*(-?\\\\w+)\\\\s*\\\\]\");\n        try (Scanner tokenScanner = new Scanner(tokens))\n        {\n            while (tokenScanner.findInLine(rangePattern) != null)\n            {\n                MatchResult range = tokenScanner.match();\n                Token startToken = factory.fromString(range.group(1));\n                Token endToken = factory.fromString(range.group(2));\n                logger.info(\"adding range: ({},{}]\", startToken, endToken);\n                ranges.add(new Range<>(startToken, endToken));\n            }\n            if (tokenScanner.hasNext())\n                throw new IllegalArgumentException(\"Unexpected string: \" + tokenScanner.next());\n        }\n\n        // Ensure all specified ranges are actually ranges owned by this host\n        RangesAtEndpoint localReplicas = StorageService.instance.getLocalReplicas(keyspace);\n        RangesAtEndpoint.Builder streamRanges = new RangesAtEndpoint.Builder(getBroadcastAddressAndPort(), ranges.size());\n        for (Range<Token> specifiedRange : ranges)\n        {\n            boolean foundParentRange = false;\n            for (Replica localReplica : localReplicas)\n            {\n                if (localReplica.contains(specifiedRange))\n                {\n                    streamRanges.add(localReplica.decorateSubrange(specifiedRange));\n                    foundParentRange = true;\n                    break;\n                }\n            }\n            if (!foundParentRange)","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/Rebuild.java#L188-L224","documentation":"rangesForRebuildWithTokens parses the tokens string as a sequence of (start,end] range literals; after all matched ranges are consumed, any leftover input in the scanner means malformed trailing content, which is rejected.","triggerScenarios":"Calling rebuild with a tokens argument containing anything after valid range tokens — e.g. trailing comma, stray text, or a bare token instead of a (start,end] pair.","commonSituations":"Hand-written token list with typos; quoting issues in shell causing partial parsing; mixing bare tokens with ranges; copy-paste introducing extra characters.","solutions":["Provide tokens strictly as comma-separated (start,end] ranges, e.g. \"(-9223372036854775808,-4611686018427387904]\",\"(-4611686018427387904,0]\"","Check shell quoting so the whole tokens string reaches rebuild intact","Remove any trailing separators or non-range text"],"exampleFix":"// before\nnodetool rebuild -ks ks1 --tokens \"(-10,-5],\"\n// after (no trailing comma)\nnodetool rebuild -ks ks1 --tokens \"(-10,-5]\"","handlingStrategy":"validation","validationCode":"// tokens must be only (start,end] ranges\nPattern RANGE = Pattern.compile(\"\\\\(([^,]+),([^]]+)\\\\]\");\nif (!RANGE.matcher(tokens).replaceAll(\"\").trim().isEmpty())\n    throw new IllegalArgumentException(\"malformed tokens argument: \" + tokens);","typeGuard":null,"tryCatchPattern":"try { rebuild(ks, tokens); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith(\"Unexpected string\")) rebuild(ks, sanitizeTokens(tokens)); else throw e; }","preventionTips":["Quote the --tokens argument in shell to avoid partial parsing","Generate range strings programmatically from describering output","Strip trailing commas/whitespace before passing tokens"],"tags":["parsing","arguments","format","rebuild"],"backgroundTag":"invalid-argument-format","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}