apache/cassandra · error · IllegalArgumentException

Start and end tokens must be different.

Error message

Start and end tokens must be different.

What it means

RepairOption.parseRanges parses user-supplied token ranges of the form begin:end and throws IllegalArgumentException if begin and end tokens are equal, because Range(token,token) is an empty range and not a valid repair range (ranges are [start, end)).

Source

Thrown at src/java/org/apache/cassandra/repair/messages/RepairOption.java:92

    public static Set<Range<Token>> parseRanges(String rangesStr, IPartitioner partitioner)
    {
        if (rangesStr == null || rangesStr.isEmpty())
            return Collections.emptySet();

        Set<Range<Token>> ranges = new HashSet<>();
        StringTokenizer tokenizer = new StringTokenizer(rangesStr, ",");
        while (tokenizer.hasMoreTokens())
        {
            String[] rangeStr = tokenizer.nextToken().split(":", 2);
            if (rangeStr.length < 2)
            {
                continue;
            }
            Token parsedBeginToken = partitioner.getTokenFactory().fromString(rangeStr[0].trim());
            Token parsedEndToken = partitioner.getTokenFactory().fromString(rangeStr[1].trim());
            if (parsedBeginToken.equals(parsedEndToken))
            {
                throw new IllegalArgumentException("Start and end tokens must be different.");
            }
            ranges.add(new Range<>(parsedBeginToken, parsedEndToken));
        }
        return ranges;
    }

    /**
     * Construct RepairOptions object from given map of Strings.
     * <p>
     * Available options are:
     *
     * <table>
     *     <caption>Repair Options</caption>
     *     <thead>
     *         <tr>
     *             <th>key</th>
     *             <th>value</th>
     *             <th>default (when key not given)</th>

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Remove the degenerate range and provide distinct start/end tokens
  2. To repair the full ring, omit range options entirely (defaults to local node's ranges)
  3. Use proper wrap-around notation (minToken, token] for wrap-around coverage instead of x:x

Example fix

// before
nodetool repair ks --ranges 1:1
// after
nodetool repair -pr ks  # or use distinct tokens like 1:100
Defensive patterns

Strategy: validation

Validate before calling

for (String r : rangeSpecs) {
    String[] parts = r.split(":");
    if (parts.length == 2 && parts[0].trim().equals(parts[1].trim()))
        throw new IllegalArgumentException("Degenerate range " + r + ": start and end tokens must differ");
}

Try / catch

try { RepairOption.parse(opts, partitioner); }
catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Start and end tokens must be different"))
        logger.warn("Fix range arguments; drop degenerate ranges", e);
    else throw e;
}

Prevention

When it happens

Trigger: Calling nodetool repair with --ranges (or RepairOption.ranges()) where a range string has identical start and end tokens, e.g. `1:1`.

Common situations: Hand-written range lists in scripts; misunderstanding that (x,x) means the full ring instead of an empty range; automation generating degenerate range strings.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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