alibaba/spring-cloud-alibaba · error · ParseException

Day of month values must be between 1 and 31

Error message

Day of month values must be between 1 and 31

What it means

Thrown in addToSet when a DAY_OF_MONTH value (or range end) is outside 1-31, unless it is ALL_SPEC or NO_SPEC (guard at CronExpression.java:781-785). Day-of-month is 1-based; 0 and >31 are invalid.

Source

Thrown at spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-schedulerx/src/main/java/com/alibaba/cloud/scheduling/schedulerx/util/CronExpression.java:782

		final 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);
			}
		}
		else if (type == DAY_OF_WEEK) {
			if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT)
					&& (val != NO_SPEC_INT)) {
				throw new ParseException(
						"Day-of-Week values must be between 1 and 7", -1);
			}
		}

		if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) {

View on GitHub (pinned to 115d590110)

Solutions

  1. Use day-of-month values 1-31, e.g. '0' -> '1' or '32' -> 'L' for last day.
  2. For end-of-month use 'L' rather than guessing 28/29/30/31.
  3. Recount the six fields.

Example fix

// before
new CronExpression("0 0 0 0 * ?");
// after
new CronExpression("0 0 0 1 * ?"); // 1st of every month
Defensive patterns

Strategy: validation

Validate before calling

// Day-of-month(field 3) must be 1..31 (ignoring '*', '?', 'L').
static boolean domInRange(String[] fields) {
    if (fields.length < 4) return false;
    String f = fields[3];
    if (f.equals("*") || f.equals("?") || f.equals("L") || f.startsWith("L")) return true;
    return inRange(f, 1, 31);
}
private static boolean inRange(String f, int lo, int hi) {
    for (String part : f.split("[-,/LW#]")) {
        if (part.isEmpty()) continue;
        try { int v = Integer.parseInt(part); if (v < lo || v > hi) return false; }
        catch (NumberFormatException e) { /* ignore */ }
    }
    return true;
}

Try / catch

try {
    CronExpression cron = new CronExpression(raw);
} catch (ParseException e) {
    throw new IllegalArgumentException("Invalid cron expression: " + raw, e);
}

Prevention

When it happens

Trigger: `new CronExpression("0 0 0 0 * ?")` (day=0), or `0 0 0 32 * ?` (day=32), or a range like `0 0 0 1-32 * ?`.

Common situations: 0-based day assumption, an off-by-one, or a field-shift placing a month/year value into day-of-month. Also 'last day' intent mistakenly written as a high literal instead of 'L'.

Related errors


AI-assisted analysis of alibaba/spring-cloud-alibaba@115d590110 (2026-08-14). Data as JSON: /api/errors/de3edd26c0ade425. Report an issue: GitHub.