apache/cassandra · error · IllegalArgumentException

--from-epoch (%d) must be less than or equal to --to-epoch (

Error message

--from-epoch (%d) must be less than or equal to --to-epoch (%d)

What it means

validateEpochRange guards the offline metadata dump's epoch window options. If both --from-epoch and --to-epoch are supplied and from is greater than to, the range is nonsensical and an IllegalArgumentException with the formatted values is thrown before any log reading starts.

Source

Thrown at src/java/org/apache/cassandra/tools/OfflineClusterMetadataDump.java:454

        }

        static private Epoch previousEpoch(Epoch epoch)
        {
            if (UPGRADE_GOSSIP.equals(epoch) || UPGRADE_STARTUP.equals(epoch))
                return epoch;
            if (EMPTY.equals(epoch) || FIRST.equals(epoch))
                return EMPTY;
            return Epoch.create(epoch.getEpoch() - 1);
        }

        /**
         * Validates that the from-epoch is not greater than to-epoch.
         */
        protected void validateEpochRange(Long fromEpoch, Long toEpoch)
        {
            if (fromEpoch != null && toEpoch != null && fromEpoch > toEpoch)
            {
                throw new IllegalArgumentException(
                    String.format("--from-epoch (%d) must be less than or equal to --to-epoch (%d)",
                                  fromEpoch, toEpoch));
            }
        }

        /**
         * Processes entries from an EntryHolder, detecting and reporting gaps in epochs.
         */
        @VisibleForTesting
        static ImmutableList<Entry> processEntriesWithGapDetection(LogReader.EntryHolder entryHolder,
                                                                   Epoch startEpoch,
                                                                   Output out)
        {
            ImmutableList.Builder<Entry> entries = ImmutableList.builder();
            Epoch prevEpoch = startEpoch;
            List<String> gaps = new ArrayList<>();

            for (Entry e : (Iterable<Entry>) entryHolder::iterator)

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Swap the values so --from-epoch <= --to-epoch
  2. Validate ordering in the wrapping script before invoking the tool
  3. Omit one of the flags if you only need a lower or upper bound

Example fix

// before
--from-epoch 100 --to-epoch 50
// after
--from-epoch 50 --to-epoch 100
Defensive patterns

Strategy: validation

Validate before calling

if (fromEpoch != null && toEpoch != null && fromEpoch > toEpoch)
    throw new IllegalArgumentException("--from-epoch must be <= --to-epoch");

Try / catch

try { dump.run(...); }
catch (IllegalArgumentException e) { System.err.println("Bad epoch range: " + e.getMessage()); }

Prevention

When it happens

Trigger: Invoking OfflineClusterMetadataDump with, e.g., --from-epoch 100 --to-epoch 50; also triggered when a caller passes reversed longs to validateEpochRange programmatically.

Common situations: Typo'd or swapped argument order in shell scripts; copy-paste of epoch values in the wrong order; automating dumps with computed epoch variables that got transposed.

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/de2da426b6845f08. Report an issue: GitHub.