jeecgboot/JeecgBoot · 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
'?' (NO_SPEC) is semantically allowed only in the day-of-month or day-of-week fields, because those two fields are mutually exclusive in Quartz. If the parser encounters '?' while parsing SECOND, MINUTE, HOUR, or MONTH (type != DAY_OF_WEEK and != DAY_OF_MONTH), it throws this. It enforces the Quartz rule that you specify '?' in one day field to let the other be set.
Source
Thrown at jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java:620
"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) {
if (!daysOfMonth.isEmpty() && daysOfMonth.last() == 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);View on GitHub (pinned to 96fb33f5ec)
Solutions
- Use '*' (not '?') for 'every value' in SECOND/MINUTE/HOUR/MONTH.
- Reserve '?' exclusively for the dom-or-dow field you are leaving unspecified.
- Validate that '?' appears only in field positions 4 (dom) or 6 (dow) of the expression.
Example fix
// before - '?' in the minute field String cron = "0 ? 0 * * ?"; // Illegal: ? in MINUTE // after - '*' for every minute, '?' only in a day field String cron = "0 * 0 * * ?";
Defensive patterns
Strategy: validation
Validate before calling
// '?' is only legal in dom (index 3) or dow (index 5) of the 6-field array.
public static String validateQuestionMarkPlacement(String expr) {
String[] f = expr.trim().split("\\s+");
for (int i = 0; i < f.length && i < 6; i++) {
if (f[i].contains("?") && i != 3 && i != 5) {
return "'?' is only allowed in day-of-month or day-of-week, found in field " + (i + 1);
}
}
return null;
} Type guard
public static boolean isQuestionMarkInValidField(String[] fields) {
for (int i = 0; i < fields.length && i < 6; i++) {
if (fields[i].contains("?") && i != 3 && i != 5) return false;
}
return true;
} Try / catch
try {
new CronExpression(expr);
} catch (ParseException e) {
if (e.getMessage().contains("Day-of-Month or Day-of-Week")) {
return "Use '*' (not '?') in second/minute/hour/month; reserve '?' for the day fields. " + e.getMessage();
}
throw e;
} Prevention
- Only allow '?' in the dom or dow field positions; reject it elsewhere.
- Educate users that '*' means 'every', '?' means 'unspecified' for day fields only.
- Default non-day fields to '*' in any cron builder template.
When it happens
Trigger: A '?' in a non-day field: '0 ? 0 * * *' (MINUTE='?'), '? * * * * *' (SECOND), '0 0 0 * ? *' is fine but '0 0 0 * 1 ? *' with MONTH or '0 ? 0 * * ?' is not. Common when a developer copies the dom/dow '?' pattern into every field.
Common situations: Misunderstanding '?' as a generic wildcard; putting '?' in seconds/minutes to mean 'every'; templates that fill unused fields with '?'.
Related errors
- Illegal characters for this position: '{sub}'
- Illegal character after '?': {s.charAt(i)}
- '?' can only be specified for Day-of-Month -OR- Day-of-Week.
- 'L' not expected in seconds, minutes or hours fields.
- Illegal cron expression format ({e})
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/04d3469dfbcbd1db.
Report an issue: GitHub.