flowable/flowable-engine · error · java.text.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
CronExpression validates the DAY_OF_MONTH field during parsing in addToSet: the day value and the end of any day range must be between 1 and 31 (the wildcard '*' sentinel and the '?' NO_SPEC sentinel are exempt). Otherwise new CronExpression(String) throws a java.text.ParseException with this message at construction time.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java:985
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);
}
} 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) {
if (val != -1) {
set.add(val);
} else {
set.add(NO_SPEC);
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Correct the day-of-month token to be in 1-31 (no zero-based indexing).
- Verify field order in the expression (sec min hour day month dow) — a shifted field often causes out-of-range values.
- For 'last day of month' use 'L' where supported, or compute the date programmatically instead of day 0/32.
- Pre-validate with CronExpression.isValidExpression() and reject the configuration at startup.
Example fix
// before
CronExpression expr = new CronExpression("0 0 0 0 * ?"); // day 0 invalid
// after
CronExpression expr = new CronExpression("0 0 0 1 * ?"); Defensive patterns
Strategy: validation
Validate before calling
if (!CronExpression.isValidExpression(cron)) {
throw new IllegalArgumentException("Invalid cron: day-of-month must be 1-31 in " + cron);
}
CronExpression expr = new CronExpression(cron); Try / catch
try {
CronExpression expr = new CronExpression(cron);
} catch (ParseException e) {
log.error("Invalid day-of-month in cron '{}'", cron, e);
throw new ConfigurationException(e);
} Prevention
- Days are 1-based in cron: 1-31, no day 0
- Check field order (sec min hour day month dow) — a shifted field often produces out-of-range days
- Use 'L' or '?' conventions for last-day/no-specific semantics
- Pre-validate user-entered timer definitions
When it happens
Trigger: new CronExpression(cronString) with a day-of-month token of 0, negative, or >31, e.g. '0 0 0 32 * ?' or '0 0 0 0 * ?'. Also a range whose end exceeds 31 such as '0 0 0 30-32 * ?'.
Common situations: Typo'd cron fields in BPMN timeCycle definitions (fields shifted so a month number lands in the day slot); zero-based day generation (0-30 instead of 1-31) when converting from an API that indexes days from 0; 'day 0' meaning 'last day' confusion.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Hour values must be between 0 and 23
- Month values must be between 1 and 12
- '#' option is not valid here. (pos=
- Unexpected character '<c>' after '/'
- Minute and Second values must be between 0 and 59
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/971366d2acfdfaaa.
Report an issue: GitHub.