apache/cassandra · error · IllegalArgumentException

Invalid duration. The %s should be after %s

Error message

Invalid duration. The %s should be after %s

What it means

Thrown by Duration.Builder.validateOrder when duration units appear out of descending order. The CQL duration grammar requires units from largest to smallest (years, months, weeks, days, hours, minutes, seconds, ...). If a unit's index is less than or equal to the previously parsed unit's index (and not a duplicate), the literal is invalid.

Source

Thrown at src/java/org/apache/cassandra/cql3/functions/types/Duration.java:605

            "Invalid duration. The total number of %s must be less or equal to %s",
            unitName,
            Integer.MAX_VALUE);
        }

        /**
         * Validates that the duration values are added in the proper order.
         *
         * @param unitIndex the unit index (e.g. years=1, months=2, ...)
         */
        private void validateOrder(int unitIndex)
        {
            if (unitIndex == currentUnitIndex)
                throw new IllegalArgumentException(
                String.format(
                "Invalid duration. The %s are specified multiple times", getUnitName(unitIndex)));

            if (unitIndex <= currentUnitIndex)
                throw new IllegalArgumentException(
                String.format(
                "Invalid duration. The %s should be after %s",
                getUnitName(currentUnitIndex), getUnitName(unitIndex)));

            currentUnitIndex = unitIndex;
        }

        /**
         * Returns the name of the unit corresponding to the specified index.
         *
         * @param unitIndex the unit index
         * @return the name of the unit corresponding to the specified index.
         */
        private String getUnitName(int unitIndex)
        {
            switch (unitIndex)
            {
                case 1:

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Reorder the components from largest unit to smallest (e.g. '3d 1y' -> '1y 3d')
  2. Split and sort the duration string by unit rank before passing it to Duration.from
  3. Catch IllegalArgumentException and show the expected ordering rule to the user

Example fix

// before
Duration.from("5s 2h 1d")
// after
Duration.from("1d 2h 5s")
Defensive patterns

Strategy: validation

Validate before calling

private static final java.util.Map<String,Integer> RANK = java.util.Map.of("y",1,"mo",2,"w",3,"d",4,"h",5,"m",6,"s",7,"ms",8,"us",9,"ns",10);
static boolean unitsInOrder(String dur) {
  java.util.List<Integer> r = new java.util.ArrayList<>();
  java.util.regex.Matcher m = java.util.regex.Pattern.compile("(\\d+)(y|mo|w|d|h|m|s|ms|us|ns)").matcher(dur);
  while (m.find()) r.add(RANK.get(m.group(2)));
  for (int i = 1; i < r.size(); i++) if (r.get(i) <= r.get(i-1)) return false;
  return true;
}

Try / catch

try { Duration d = Duration.from(input); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Duration units must appear largest-to-smallest: " + input, e); }

Prevention

When it happens

Trigger: Parsing strings like Duration.from("3d 1y") or "5s 2h" — any literal where a smaller unit precedes a larger one, passed to Duration.from or used as a duration literal in CQL.

Common situations: Users writing durations in natural (ascending) order; i18n conventions where small units come first; code that sorts unit components alphabetically instead of by magnitude.

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


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