flowable/flowable-engine · error · java.text.ParseException
Hour values must be between 0 and 23
Error message
Hour values must be between 0 and 23
What it means
CronExpression (a Quartz-derived cron parser used by Flowable's ProcessEngineConfiguration clock/timer scheduler) validates each field of the cron expression when the expression is parsed via new CronExpression(String). During storeExpressionVals/addToSet, the HOUR field value (or the end of an hour range) must be in 0-23; otherwise it throws a java.text.ParseException with this message. It is thrown at construction time, before any scheduling happens.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java:981
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);
}
} 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);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Correct the hour token in the cron string to a value in 0-23 (use 0 for midnight, not 24).
- If the range end exceeds 23 (e.g. 22-25), split or clamp it: ranges that wrap midnight must be expressed as two expressions or with the '*' shorthand.
- Validate the cron string before deployment with CronExpression.isValidExpression(cronString) and surface a clear config error to the user.
- Wrap construction in try/catch (ParseException) at configuration-load time and fail fast with the offending expression in the log.
Example fix
// before
CronExpression expr = new CronExpression("0 0 24 * * ?"); // throws
// after
CronExpression expr = new CronExpression("0 0 0 * * ?"); // midnight = 0 Defensive patterns
Strategy: validation
Validate before calling
if (!CronExpression.isValidExpression(cron)) {
throw new IllegalArgumentException("Invalid cron expression: " + cron + " (hours must be 0-23)");
}
CronExpression expr = new CronExpression(cron); Try / catch
try {
CronExpression expr = new CronExpression(cron);
} catch (ParseException e) {
throw new ConfigurationException("Bad hour field in cron: " + cron, e);
} Prevention
- Validate cron strings with CronExpression.isValidExpression() at config load time
- Remember midnight is 0, never 24
- Use hour abbreviations/ranges only within 0-23
- Fail fast at startup, not at first schedule fire
When it happens
Trigger: Calling new CronExpression(cronString) (directly or via CronExpression.getInstance) with an hour token outside 0-23, e.g. '0 0 24 * * ?' or a range whose end exceeds 23 like '0 0 22-25 * * ?'. Only values outside the range and not the '*' ALL_SPEC sentinel trigger it.
Common situations: Hand-written cron strings in BPMN timer definitions or flowable.cfg job configurations; converting from formats that allow 0-24 hours; off-by-one errors like 24 for midnight instead of 0; dynamically generated ranges whose end was computed incorrectly.
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
- Day of month values must be between 1 and 31
- 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/72bbebda5014c29a.
Report an issue: GitHub.