jeecgboot/JeecgBoot · error · ParseException
Illegal character after '?': {s.charAt(i)}
Error message
Illegal character after '?': {s.charAt(i)} What it means
After a '?' character, the parser advances i and checks that the following character is a space or tab. If (i+1) < length and the char at i is not a space (and the char at i+1 is not a tab), this is thrown. '?' must stand alone as a whole field value, so any trailing non-whitespace like '?5' or '?*' is illegal.
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:616
}
} 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) {
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;
}View on GitHub (pinned to 96fb33f5ec)
Solutions
- Use '?' only as the complete field value - it must be the only token in that field.
- Replace '?X' with either '?' (no specific value) or the explicit value 'X'.
- Remember '?' is the counterpart to '*': use it in dom or dow to say 'do not care', required when the other of dom/dow is specified.
Example fix
// before - '?' glued to a digit String cron = "0 0 0 ?5 * ?"; // Illegal character after '?': 5 // after - '?' as whole field String cron = "0 0 0 ? * ?";
Defensive patterns
Strategy: validation
Validate before calling
// '?' must be a standalone field value with no adjacent token.
public static String validateQuestionMarkField(String field) {
if (field == null) return null;
if (field.contains("?") && !field.trim().equals("?")) {
return "'?' must be the whole field, found: " + field;
}
return null;
} Type guard
public static boolean isStandaloneQuestionMark(String field) {
return field != null && field.trim().equals("?");
} Try / catch
try {
new CronExpression(expr);
} catch (ParseException e) {
if (e.getMessage().startsWith("Illegal character after '?'")) {
return "'?' must stand alone in its field; remove the trailing character. " + e.getMessage();
}
throw e;
} Prevention
- Enforce that any field containing '?' equals exactly '?'.
- Treat '?' and '*' as mutually exclusive within a single field.
- In the UI, present '?' as a toggle, not as a typable character alongside others.
When it happens
Trigger: A '?' glued to another token: '0 0 0 ?5 * *' (dow '?5'), '0 0 0 * * ?*' (trailing '*'), or a '?' in the middle of a field like '0 0 0 ?-1 * *'. Note the condition is a logical AND of two checks, so single trailing non-space may or may not trip depending on the next char, but any non-whitespace directly after '?' in a multi-char field triggers it.
Common situations: Typing '?' next to other characters thinking it means 'any'; mixing '?' and '*' in the same field; malformed programmatic concatenation.
Related errors
- '?' can only be specified for Day-of-Month -OR- Day-of-Week.
- Illegal cron expression format ({e})
- Invalid Month value: '{sub}'
- Invalid Day-of-Week value: '{sub}'
- A numeric value between 1 and 5 must follow the '#' option
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/40406f069a5fed2e.
Report an issue: GitHub.