flowable/flowable-engine · error · ParseException
'?' can only be specified for Day-of-Month or Day-of-Week.
Error message
'?' can only be specified for Day-of-Month or Day-of-Week.
What it means
Thrown when '?' appears in a field other than Day-of-Month or Day-of-Week. In Quartz-style cron, '?' means 'no specific value' and is only legal in the two day fields; the parser enforces this to prevent ambiguity between which day field drives the schedule.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java:618
}
} else {
throw new ParseException("Illegal characters for this position: '" + sub + "'", i);
}
if (eval != -1) {
incr = 1;
}
addToSet(sval, eval, incr, type);
return (i + 3);
}
if (c == '?') {
i++;
if ((i + 1) < s.length() && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) {
throw new ParseException("Illegal character after '?': " + s.charAt(i), i);
}
if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) {
throw new ParseException("'?' can only be specified for Day-of-Month or Day-of-Week.", i);
}
if (type == DAY_OF_WEEK && !lastdayOfMonth) {
int val = daysOfMonth.last();
if (val == NO_SPEC_INT) {
throw new ParseException("'?' can only be specified for Day-of-Month -OR- Day-of-Week.", i);
}
}
addToSet(NO_SPEC_INT, -1, 0, type);
return i;
}
if (c == '*' || c == '/') {
if (c == '*' && (i + 1) >= s.length()) {
addToSet(ALL_SPEC_INT, -1, incr, type);
return i + 1;
} else if (c == '/' && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t')) {
throw new ParseException("'/' must be followed by an integer.", i);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Use '*' instead of '?' in seconds, minutes, hours, month, and year fields.
- Reserve '?' for exactly one of Day-of-Month or Day-of-Week (the other should usually be '*' or a concrete value).
- Sanitize user input: strip/replace '?' outside the two day fields before parsing.
- Show a field-by-field cron builder UI so users never hand-type '?' in the wrong slot.
Example fix
// before
new CronExpression("0 ? 12 * * ?");
// after
new CronExpression("0 * 12 * * ?"); Defensive patterns
Strategy: validation
Validate before calling
// '?' is only legal in fields 4 (day-of-month) and 6 (day-of-week)
String[] p = expr.trim().split("\\s+");
for (int i = 0; i < p.length; i++) {
if (p[i].contains("?") && i != 3 && i != 5) {
throw new IllegalArgumentException("'?' not allowed in field " + (i + 1));
}
} Try / catch
try {
new CronExpression(expr);
} catch (java.text.ParseException e) {
throw new IllegalArgumentException("'?' only valid for Day-of-Month/Day-of-Week in: " + expr, e);
} Prevention
- Use '*' for 'every' in seconds/minutes/hours/month/year
- Reserve '?' for exactly one day field
- Offer structured cron builders instead of free-text input
When it happens
Trigger: new CronExpression("0 ? 12 * * ?") — '?' in the minutes field; using '?' as a wildcard in seconds, minutes, hours, month, or year fields, often from copying the '?' from the day fields to others.
Common situations: Users generalizing 'the ? goes somewhere' after seeing it in day fields; auto-generated UI forms allowing '?' in every field; migration from other schedulers whose dialects permit '?' anywhere.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid Day-of-Week value: '
- A numeric value between 1 and 5 must follow the '#' option
- Illegal characters for this position: '
- Illegal character after ?:
- '?' can only be specified for Day-of-Month -OR- Day-of-Week.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b084441651924c42.
Report an issue: GitHub.