jeecgboot/JeecgBoot · error · ParseException

Unexpected end of expression.

Error message

Unexpected end of expression.

What it means

Thrown by CronExpression's parser when the expression has fewer than 6 fields after tokenization completes. The parser tracks which field it has processed via exprOn (starting at SECOND=1 through YEAR=7). If after consuming all tokens, exprOn is still at or below DAY_OF_WEEK (field 5), the expression is too short. A valid Quartz cron requires at least 6 fields (seconds through day-of-week). The error position is set to the expression length.

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:507

                // throw an exception if L is used with other days of the week
                if(exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1  && expr.contains(",")) {
                    throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1);
                }
                if(exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') +1) != -1) {
                    throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1);
                }

                StringTokenizer vTok = new StringTokenizer(expr, ",");
                while (vTok.hasMoreTokens()) {
                    String v = vTok.nextToken();
                    storeExpressionVals(0, v, exprOn);
                }

                exprOn++;
            }

            if (exprOn <= DAY_OF_WEEK) {
                throw new ParseException("Unexpected end of expression.",
                        expression.length());
            }

            if (exprOn <= YEAR) {
                storeExpressionVals(0, "*", YEAR);
            }

            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);

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Ensure the expression has at least 6 fields: add a leading seconds field (usually '0') to 5-field Unix cron expressions.
  2. Convert Unix '0 6 * * *' to Quartz '0 0 6 * * ?' (note: also change '*' in day-of-week to '?').
  3. Validate field count before constructing the CronExpression: split by whitespace and assert length is 6 or 7.
  4. Check for template/variable substitution issues that may truncate the expression.

Example fix

// before: 5-field Unix cron (missing seconds field)
String cron = "0 6 * * *";
CronExpression expr = new CronExpression(cron);

// after: 6-field Quartz cron (seconds minutes hours dom month dow)
String cron = "0 0 6 * * ?";
CronExpression expr = new CronExpression(cron);
Defensive patterns

Strategy: validation

Validate before calling

// Validate minimum field count before parsing
public void validateCronMinFields(String expression) {
    if (expression == null || expression.trim().isEmpty()) {
        throw new IllegalArgumentException("Cron expression cannot be null or empty");
    }
    int count = new StringTokenizer(expression, " \t").countTokens();
    if (count < 6) {
        throw new IllegalArgumentException(
            "Cron expression must have at least 6 fields (seconds through day-of-week), found " + count);
    }
}

Type guard

// Check expression has at least 6 whitespace-separated fields
public boolean hasMinCronFields(String expression) {
    if (expression == null || expression.trim().isEmpty()) return false;
    return new StringTokenizer(expression, " \t").countTokens() >= 6;
}

Try / catch

try {
    CronExpression cron = new CronExpression(expression);
} catch (ParseException e) {
    if (e.getMessage().contains("Unexpected end")) {
        throw new IllegalArgumentException(
            "Cron expression is too short. Quartz requires at least 6 fields (add a seconds field).", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Providing a 5-field Unix-style cron expression like '0 6 * * *' (no seconds field). Providing a partial expression like '0 0 12 * *' (only 5 fields). Empty or whitespace-only string passed as the cron expression. An expression with only 1-4 fields due to a copy-paste truncation.

Common situations: Using standard Linux crontab syntax (5 fields) which Quartz does not accept — Quartz requires a leading seconds field. Truncated expression from string manipulation or template substitution failure. Copying a cron expression from a non-Quartz system. Variable interpolation that produces fewer fields than expected.

Related errors


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