jeecgboot/JeecgBoot · error · ParseException
Illegal cron expression format ({e})
Error message
Illegal cron expression format ({e}) What it means
Thrown by the outer catch-all in CronExpression.buildExpression(): any non-ParseException raised while tokenizing the 6-7 cron fields (NumberFormatException, StringIndexOutOfBoundsException, etc.) is wrapped and rethrown as a ParseException. It indicates the parser hit an unexpected internal failure on a structurally malformed expression, so the original cause is concatenated into the message via {e}. Because {e} is the raw exception, the actionable detail lives in its class name and message, not in this generic header.
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:531
}
TreeSet<Integer> dow = getSet(DAY_OF_WEEK);
TreeSet<Integer> dom = getSet(DAY_OF_MONTH);
// Copying the logic from the UnsupportedOperationException below
boolean dayOfMSpec = !dom.contains(NO_SPEC);
boolean dayOfWSpec = !dow.contains(NO_SPEC);
if (!dayOfMSpec || dayOfWSpec) {
if (!dayOfWSpec || dayOfMSpec) {
throw new ParseException(
"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", 0);
}
}
} catch (ParseException pe) {
throw pe;
} catch (Exception e) {
throw new ParseException("Illegal cron expression format ("
+ e + ")", 0);
}
}
protected int storeExpressionVals(int pos, String s, int type)
throws ParseException {
int incr = 0;
int i = skipWhiteSpace(pos, s);
if (i >= s.length()) {
return i;
}
char c = s.charAt(i);
if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW")) && (!s.matches("^L-[0-9]*[W]?"))) {
String sub = s.substring(i, i + 3);
int sval = -1;
int eval = -1;
if (type == MONTH) {View on GitHub (pinned to 96fb33f5ec)
Solutions
- Read the wrapped exception in {e}: its class (e.g. NumberFormatException, StringIndexOutOfBoundsException) tells you which field/token is at fault, then fix that specific token.
- Confirm the expression has the 6 or 7 Quartz fields (sec min hour dom month dow [year]) separated by single spaces, not the 5-field Linux crond format.
- Validate the expression in isolation with 'new CronExpression(cleaned)' inside a unit test before persisting it as a job schedule.
- If the cause still is unclear, enable DEBUG on the xxl-job admin to log the raw cron string at submission time and re-parse it locally.
Example fix
// before - 5-field Linux cron fed to Quartz parser String cron = "0 5 * * *"; // throws Illegal cron expression format CronExpression ce = new CronExpression(cron); // after - 6-field Quartz cron (sec min hour dom month dow) String cron = "0 0 5 * * ?"; CronExpression ce = new CronExpression(cron);
Defensive patterns
Strategy: try-catch
Validate before calling
// Validate a cron expression before persisting it as a job schedule.
// Returns null on success, or a human-readable reason on failure.
public static String validateCron(String expr) {
if (expr == null || expr.trim().isEmpty()) return "cron expression is empty";
String[] fields = expr.trim().split("\\s+");
if (fields.length < 6 || fields.length > 7) {
return "expected 6 or 7 fields (sec min hour dom month dow [year]), got " + fields.length;
}
try {
new com.xxl.job.admin.business.scheduler.cron.CronExpression(expr);
return null; // ok
} catch (java.text.ParseException e) {
return e.getMessage();
}
} Type guard
// Lightweight structural type guard before invoking the parser.
// True only for plausible Quartz cron shapes.
public static boolean looksLikeQuartzCron(String expr) {
if (expr == null) return false;
String[] f = expr.trim().split("\\s+");
if (f.length < 6 || f.length > 7) return false;
java.util.regex.Pattern p = java.util.regex.Pattern.compile("[0-9*/,\\-?LW#A-Za-z]+");
for (String field : f) if (!p.matcher(field).matches()) return false;
return true;
} Try / catch
try {
CronExpression ce = new CronExpression(userCron);
// ... register schedule with ce
} catch (java.text.ParseException e) {
// 280 surfaces the wrapped cause inside e.getMessage(); surface it to the user.
log.warn("Invalid cron '{}' from user: {}", userCron, e.getMessage());
throw new IllegalArgumentException("Invalid schedule expression: " + e.getMessage(), e);
} Prevention
- Always run user-supplied cron strings through new CronExpression(expr) in a unit test before saving them to the job config table.
- Reject 5-field Linux crond strings at the controller boundary (require 6-7 fields).
- Log the exact cron string that failed so the wrapped cause in {e} can be diagnosed.
- Provide a cron builder UI that emits valid Quartz syntax rather than accepting free text.
When it happens
Trigger: Constructing 'new CronExpression(expr)' (or XxlJob scheduling a job whose cron field fails). Concrete producers: a field that is empty or has a trailing operator like '0 0 0 /5 * ?', a substring index overrun when a field has <3 chars but starts with A-Z, or a numeric parse on a non-numeric token that slips past the earlier alpha branch. Any RuntimeException during storeExpressionVals/getValue that is not itself a ParseException lands here.
Common situations: Operators pasting a cron string from a tutorial that uses Linux crond syntax (5 fields, e.g. '0 5 * * *') into a Quartz/xxl-job field that expects 6-7 fields; missing or duplicate spaces between fields; a copy/paste that drops a trailing segment; upgrading xxl-job across a version where a previously tolerated field shape now throws.
Related errors
- Invalid Month value: '{sub}'
- Invalid Day-of-Week value: '{sub}'
- A numeric value between 1 and 5 must follow the '#' option
- Illegal characters for this position: '{sub}'
- Illegal character after '?': {s.charAt(i)}
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/48c87f634c91fbea.
Report an issue: GitHub.