{"record":{"id":"4a3cfe44cea5085f","repo":"apache/cassandra","slug":"invalid-to-specify-randomiser-when-no-range-specif","errorCode":null,"errorMessage":"Invalid to specify randomiser when no range specified: '${original}'","messagePattern":"Invalid to specify randomiser when no range specified: '(.+?)'","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/RetryStrategy.java","lineNumber":313,"sourceCode":"                        break;\n                }\n                end = next;\n            }\n            if (end != spec.length())\n                spec = spec.substring(0, end);\n        }\n\n        Matcher m = PARSE.matcher(spec);\n        if (!m.matches())\n            throw new IllegalArgumentException(\"Invalid specification: '\" + spec + \"'; does not match \" + PARSE);\n\n        long minMin = parseInMicros(m.group(\"minmin\"), 0);\n        long maxMax = parseInMicros(m.group(\"maxmax\"), Long.MAX_VALUE);\n        Wait max = TimeoutStrategy.parseWait(m.group(\"max\"), latencies);\n        String minSpec = m.group(\"min\");\n        Wait min = minSpec == null ? null : TimeoutStrategy.parseWait(minSpec, latencies);\n        if (min == null && randomizer != null)\n            throw new IllegalArgumentException(\"Invalid to specify randomiser when no range specified: '\" + original + '\\'');\n        if (min instanceof Wait.Constant && minMin != 0)\n            throw new IllegalArgumentException(\"Invalid to specify an absolute minimum constant when the min bound is itself a constant: '\" + original + '\\'');\n        long maxMin = parseInMicros(m.group(\"maxmin\"), Long.MAX_VALUE);\n        if (min instanceof Wait.Constant && maxMin != Long.MAX_VALUE)\n            throw new IllegalArgumentException(\"Invalid to specify an absolute max(min) constant when the min bound is itself a constant: '\" + original + '\\'');\n        if (max instanceof Wait.Constant && maxMax != Long.MAX_VALUE)\n            throw new IllegalArgumentException(\"Invalid to specify an absolute maximum constant when the max bound is itself a constant: '\" + original + '\\'');\n        if (randomizer == null)\n            randomizer = randomizers.uniform();\n        return new RetryStrategy(randomizer, minMin, min, maxMin, max, maxMax, retries);\n    }\n\n    @VisibleForTesting\n    protected static WaitRandomizer parseWaitRandomizer(String input)\n    {\n        Matcher m = RANDOMIZER.matcher(input);\n        if (!m.matches())\n            throw new IllegalArgumentException(input + \" does not match\" + RANDOMIZER);","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/RetryStrategy.java#L295-L331","documentation":"A randomizer spreads the wait over a [min,max] range; it is meaningless when the spec defines only a fixed max wait with no min (min == null). RetryStrategy.parse() throws an IllegalArgumentException naming the original spec in that case.","triggerScenarios":"RetryStrategy.parse(spec, latencies) where the spec has no min bound (so min parses to null) but a randomizer is present — either via ',rnd=...' modifier or the three-arg parse(spec, latencies, randomizer) overload, e.g. \"500ms,rnd=exp(2)\".","commonSituations":"Config written for a ranged spec later simplified to a single wait while keeping the rnd clause; programmatically passing a non-null randomizer with a single-wait spec.","solutions":["Add a min bound so a range exists, e.g. \"100ms..500ms,rnd=exp(2)\"","Remove the rnd modifier if a fixed wait is intended","Pass null as the randomizer argument to the three-arg parse overload"],"exampleFix":"// before\nRetryStrategy.parse(\"500ms,rnd=exp(2)\", latencies);\n// after\nRetryStrategy.parse(\"100ms..500ms,rnd=exp(2)\", latencies);","handlingStrategy":"validation","validationCode":"static void validateRandomizerNeedsRange(String spec, boolean randomizerSupplied) {\n    String waitPart = spec.split(\",\")[0];\n    boolean hasRange = waitPart.contains(\"..\");\n    if (randomizerSupplied && !hasRange)\n        throw new IllegalArgumentException(\"rnd requires a min..max range in spec: \" + spec);\n}","typeGuard":null,"tryCatchPattern":"try {\n    RetryStrategy strategy = RetryStrategy.parse(spec, latencies, randomizer);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Invalid to specify randomiser\")) {\n        LOG.warn(\"Randomizer ignored for non-ranged spec '{}'\", spec);\n        return RetryStrategy.parse(spec, latencies);\n    }\n    throw e;\n}","preventionTips":["Only attach rnd=... to specs with a min..max range","When simplifying a ranged spec to a fixed wait, drop the rnd clause","Pass null randomizer for single-wait specs"],"tags":["configuration","parsing","conflicting-options"],"backgroundTag":"conflicting-config-options","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"}