jeecgboot/JeecgBoot · error · IllegalArgumentException

Start year must be less than stop year

Error message

Start year must be less than stop year

What it means

Thrown as an IllegalArgumentException during range expansion when the field type is YEAR and the stop (end) year is less than the start year. Unlike other fields (seconds, hours, months, etc.) where a reversed range can wrap around using modulus arithmetic, years cannot wrap, so a reversed year range is treated as an unrecoverable configuration error.

Source

Thrown at jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java:1090

            }
            if (startAt == -1 || startAt == ALL_SPEC_INT) {
                startAt = 1970;
            }
        }

        // if the end of the range is before the start, then we need to overflow into
        // the next day, month etc. This is done by adding the maximum amount for that
        // type, and using modulus max to determine the value being added.
        int max = -1;
        if (stopAt < startAt) {
            switch (type) {
                case       SECOND : max = 60; break;
                case       MINUTE : max = 60; break;
                case         HOUR : max = 24; break;
                case        MONTH : max = 12; break;
                case  DAY_OF_WEEK : max = 7;  break;
                case DAY_OF_MONTH : max = 31; break;
                case         YEAR : throw new IllegalArgumentException("Start year must be less than stop year");
                default           : throw new IllegalArgumentException("Unexpected type encountered");
            }
            stopAt += max;
        }

        for (int i = startAt; i <= stopAt; i += incr) {
            if (max == -1) {
                // ie: there's no max to overflow over
                set.add(i);
            } else {
                // take the modulus to get the real value
                int i2 = i % max;

                // 1-indexed ranges should not include 0, and should include their max
                if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH) ) {
                    i2 = max;
                }

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Swap the range bounds so the start year is less than or equal to the stop year.
  2. If building dynamically, sort or validate the two year values before constructing the range string.
  3. Consider whether a single year value or '*' is more appropriate than a range.

Example fix

// before
String cron = "0 0 0 1 1 ? 2025-2020";  // end < start
// after
String cron = "0 0 0 1 1 ? 2020-2025";  // start < end
Defensive patterns

Strategy: validation

Validate before calling

// Validate year range: start <= stop
String yearField = fields[6]; // 7th field if present
if (yearField.contains("-")) {
    String[] parts = yearField.split("-");
    int start = Integer.parseInt(parts[0]);
    int stop = Integer.parseInt(parts[1]);
    if (stop < start) throw new IllegalArgumentException("Start year must be <= stop year");
}

Type guard

boolean isValidYearRange(String yearField) {
    if (!yearField.contains("-") || yearField.equals("*")) return true;
    String[] parts = yearField.split("-");
    try {
        return Integer.parseInt(parts[0]) <= Integer.parseInt(parts[1]);
    } catch (NumberFormatException e) {
        return false;
    }
}

Try / catch

try {
    CronExpression cron = new CronExpression(expr);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Start year must be less than stop year")) {
        // swap or fix the year range bounds
    }
    throw e;
}

Prevention

When it happens

Trigger: A cron expression with an optional 7th field (year) containing a range where the end precedes the start — e.g., year field '2020-2019', '2025-2020', or '2030-2000'.

Common situations: Developer accidentally swaps start and end in a year range; UI form inputs start/end year in wrong order; copy-paste error; dynamic generation where user-selected end year is earlier than start year.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/e822d06b7bf66ca3. Report an issue: GitHub.