xuxueli/xxl-job · error · ParseException

Minute and Second values must be between 0 and 59

Error message

Minute and Second values must be between 0 and 59

What it means

In addToSet, for the seconds or minutes field (type SECOND or MINUTE), the value must be between 0 and 59 inclusive, and the range end must also be <= 59. The only exception is ALL_SPEC_INT (99), which represents '*'. This error fires for any out-of-range value or range endpoint.

Source

Thrown at xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java:988

        return i;
    }

    protected int findNextWhiteSpace(int i, String s) {
        for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) {
        }

        return i;
    }

    protected void addToSet(int val, int end, int incr, int type)
            throws ParseException {

        TreeSet<Integer> set = getSet(type);

        if (type == SECOND || type == MINUTE) {
            if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) {
                throw new ParseException(
                        "Minute and Second values must be between 0 and 59",
                        -1);
            }
        } else if (type == HOUR) {
            if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) {
                throw new ParseException(
                        "Hour values must be between 0 and 23", -1);
            }
        } else if (type == DAY_OF_MONTH) {
            if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT)
                    && (val != NO_SPEC_INT)) {
                throw new ParseException(
                        "Day of month values must be between 1 and 31", -1);
            }
        } else if (type == MONTH) {
            if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) {
                throw new ParseException(
                        "Month values must be between 1 and 12", -1);

View on GitHub (pinned to e74c784f68)

Solutions

  1. Clamp second and minute values to 0-59 before constructing the cron string.
  2. Use '*' if you mean 'every second/minute' rather than a large number.
  3. Validate the cron expression with a dedicated validator before passing it to the CronExpression constructor.

Example fix

// before
"60 * * * * ?"
// after
"0/30 * * * * ?"
Defensive patterns

Strategy: validation

Validate before calling

// Validate seconds (field 0) and minutes (field 1) values are 0-59
String[] parts = cron.trim().split("\\s+");
for (int idx : new int[]{0, 1}) {
    if (parts.length > idx && !parts[idx].equals("*") && !parts[idx].equals("?")) {
        String numStr = parts[idx].replaceAll("[^0-9].*", "");
        if (!numStr.isEmpty()) {
            int val = Integer.parseInt(numStr);
            if (val < 0 || val > 59) throw new IllegalArgumentException("Second/minute value must be 0-59: " + val);
        }
    }
}

Type guard

boolean isValidSecondMinuteValue(String field) {
    if ("*".equals(field) || "?".equals(field)) return true;
    try {
        int val = Integer.parseInt(field.replaceAll("[^0-9].*", ""));
        return val >= 0 && val <= 59;
    } catch (NumberFormatException e) { return false; }

Try / catch

try {
    new CronExpression(cron);
} catch (ParseException e) {
    if (e.getMessage().contains("Minute and Second values must be between 0 and 59")) {
        // clamp the value to 0-59 and retry
    }
}

Prevention

When it happens

Trigger: A cron expression like '60 * * * * ?' (seconds=60), '0-60 * * * * ?' (range end 60), or '0 70 * * * ?' (minutes=70). The check at line 987 tests (val < 0 || val > 59 || end > 59) && val != ALL_SPEC_INT.

Common situations: Off-by-one errors when generating second/minute values, using 1-indexed logic on a 0-indexed field, or a UI that allows entering 60 as a maximum.

Related errors


AI-assisted analysis of xuxueli/xxl-job@e74c784f68 (2026-08-14). Data as JSON: /api/errors/9795c4699a3fda9f. Report an issue: GitHub.