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

  1. 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.
  2. 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.
  3. Validate the expression in isolation with 'new CronExpression(cleaned)' inside a unit test before persisting it as a job schedule.
  4. 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

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


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/48c87f634c91fbea. Report an issue: GitHub.