flowable/flowable-engine · error · ParseException

Illegal cron expression format (

Error message

Illegal cron expression format (

What it means

buildExpression catches any non-ParseException thrown while parsing/storing field values (NumberFormatException, StringIndexOutOfBoundsException, etc.) and rethrows it as a ParseException 'Illegal cron expression format (<exception>)'. It is the generic fallback for structurally broken expressions not caught by the specific checks.

Source

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

            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') && !"L".equals(s) && !"LW".equals(s) && !s.matches("^L-[0-9]*[W]?")) {
            String sub = s.substring(i, i + 3);
            int sval = -1;
            int eval = -1;
            if (type == MONTH) {
                sval = getMonthNumber(sub) + 1;
                if (sval <= 0) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Read the parenthesized cause in the message to identify the exact malformed token and fix it
  2. Validate the expression offline (construct CronExpression in a test or use a cron validator) before deployment
  3. Check for empty/whitespace fragments when the cron is built from templates or variables
  4. Ensure numeric fields stay within range (seconds/minutes 0-59, hours 0-23, days 1-31, months 1-12/JAN-DEC, days-of-week 1-7/SUN-SAT)

Example fix

// before
String cron = "0 0 " + hour + " * * ?"; // hour may be "" or "abc"
// after
int h = Integer.parseInt(hour); // throws NumberFormatException early, and:
if (h < 0 || h > 23) throw new IllegalArgumentException("hour out of range: " + h);
String cron = "0 0 " + h + " * * ?";
Defensive patterns

Strategy: validation

Validate before calling

// ranges and values per field
int[][] limits = {{0,59},{0,59},{0,23},{1,31},{1,12},{1,7}};
// validate each numeric token of field i against limits[i] before constructing CronExpression

Try / catch

try { new CronExpression(expr, clockReader); }
catch (ParseException e) { if (e.getMessage().startsWith("Illegal cron expression format")) { log.error("Structurally broken cron: {}", expr, e); } throw e; }

Prevention

When it happens

Trigger: new CronExpression(expr, clockReader) with garbage fields that make storeExpressionVals throw — non-numeric tokens like '0 0 abc * *', out-of-range numbers, stray characters such as '0 0 12 */ * ?', truncated ranges like '0 0 5- * ?'.

Common situations: Hand-edited BPMN timer XML with typos; values substituted into cron strings (template injection of empty or invalid fragments); locale/paste issues introducing invisible characters.

Related errors


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