flowable/flowable-engine · error · ParseException

Unexpected end of expression.

Error message

Unexpected end of expression.

What it means

After tokenizing the six standard fields, buildExpression checks exprOn; if it did not get past DAY_OF_WEEK, the expression had fewer than the required fields (second minute hour day-of-month month day-of-week). The parser requires at least 6 fields; year is the only optional field. Thrown as ParseException with the expression length as offset.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java:516

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

Solutions

  1. Add the missing seconds field (and day-of-week) — Quartz cron needs 6 or 7 fields: '0 0 12 * * ?' not '0 0 12 * *'
  2. Use '?' for whichever of day-of-month/day-of-week is unrestricted
  3. Pre-validate field count with expression.trim().split("\\s+").length >= 6 before constructing
  4. If it must stay 5-field unix cron, convert it explicitly to Quartz format

Example fix

// before
String cron = "0 0 12 * *"; // 5 fields — unix style
// after
String cron = "0 0 12 * * ?"; // 6 fields — Quartz/Flowable style (seconds added, day-of-week '?')
Defensive patterns

Strategy: validation

Validate before calling

int n = expr == null ? 0 : expr.trim().split("\\s+").length;
if (n < 6 || n > 7) throw new IllegalArgumentException("Quartz cron needs 6 or 7 fields, got " + n + ": " + expr);

Try / catch

try { new CronExpression(expr, clockReader); }
catch (ParseException e) { if (e.getMessage().contains("Unexpected end")) { /* add missing fields */ } throw e; }

Prevention

When it happens

Trigger: new CronExpression(expr, clockReader) with 5 or fewer space-separated fields, e.g. '0 0 12 * *' (unix-style 5-field cron) passed where a 6-field Quartz-style cron is required.

Common situations: Copying standard Unix crontab lines (5 fields) into Flowable timer definitions; losing a field when editing BPMN XML; whitespace/formatting issues that collapse an empty field.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/b5c2b2e82b595fc8. Report an issue: GitHub.