apache/cassandra · error · IllegalArgumentException

Invalid to specify randomiser when no range specified

Error message

Invalid to specify randomiser when no range specified: '${original}'

What it means

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.

Solutions

  1. Add a min bound so a range exists, e.g. "100ms..500ms,rnd=exp(2)"
  2. Remove the rnd modifier if a fixed wait is intended
  3. Pass null as the randomizer argument to the three-arg parse overload

Example fix

// before
RetryStrategy.parse("500ms,rnd=exp(2)", latencies);
// after
RetryStrategy.parse("100ms..500ms,rnd=exp(2)", latencies);
Defensive patterns

Strategy: validation

Validate before calling

static void validateRandomizerNeedsRange(String spec, boolean randomizerSupplied) {
    String waitPart = spec.split(",")[0];
    boolean hasRange = waitPart.contains("..");
    if (randomizerSupplied && !hasRange)
        throw new IllegalArgumentException("rnd requires a min..max range in spec: " + spec);
}

Try / catch

try {
    RetryStrategy strategy = RetryStrategy.parse(spec, latencies, randomizer);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Invalid to specify randomiser")) {
        LOG.warn("Randomizer ignored for non-ranged spec '{}'", spec);
        return RetryStrategy.parse(spec, latencies);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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)".

Common situations: 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.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/4a3cfe44cea5085f. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/service/RetryStrategy.java:313

                        break;
                }
                end = next;
            }
            if (end != spec.length())
                spec = spec.substring(0, end);
        }

        Matcher m = PARSE.matcher(spec);
        if (!m.matches())
            throw new IllegalArgumentException("Invalid specification: '" + spec + "'; does not match " + PARSE);

        long minMin = parseInMicros(m.group("minmin"), 0);
        long maxMax = parseInMicros(m.group("maxmax"), Long.MAX_VALUE);
        Wait max = TimeoutStrategy.parseWait(m.group("max"), latencies);
        String minSpec = m.group("min");
        Wait min = minSpec == null ? null : TimeoutStrategy.parseWait(minSpec, latencies);
        if (min == null && randomizer != null)
            throw new IllegalArgumentException("Invalid to specify randomiser when no range specified: '" + original + '\'');
        if (min instanceof Wait.Constant && minMin != 0)
            throw new IllegalArgumentException("Invalid to specify an absolute minimum constant when the min bound is itself a constant: '" + original + '\'');
        long maxMin = parseInMicros(m.group("maxmin"), Long.MAX_VALUE);
        if (min instanceof Wait.Constant && maxMin != Long.MAX_VALUE)
            throw new IllegalArgumentException("Invalid to specify an absolute max(min) constant when the min bound is itself a constant: '" + original + '\'');
        if (max instanceof Wait.Constant && maxMax != Long.MAX_VALUE)
            throw new IllegalArgumentException("Invalid to specify an absolute maximum constant when the max bound is itself a constant: '" + original + '\'');
        if (randomizer == null)
            randomizer = randomizers.uniform();
        return new RetryStrategy(randomizer, minMin, min, maxMin, max, maxMax, retries);
    }

    @VisibleForTesting
    protected static WaitRandomizer parseWaitRandomizer(String input)
    {
        Matcher m = RANDOMIZER.matcher(input);
        if (!m.matches())
            throw new IllegalArgumentException(input + " does not match" + RANDOMIZER);

View on GitHub (pinned to 88fd0f6a0e)