flowable/flowable-engine · error · ParseException

'L' option is not valid here. (pos=

Error message

'L' option is not valid here. (pos=

What it means

checkNext throws this when the 'L' (last-day) option character appears after a value in a field that is not DAY_OF_WEEK. 'L' is only valid as 'nL' in day-of-week, or alone in day-of-month (handled elsewhere in storeExpressionVals).

Solutions

  1. Use 'L' alone only in the day-of-month field: "0 0 0 L * ?"
  2. Use 'nL' only in the day-of-week field: "0 0 0 ? * 6L" (last Friday)
  3. Remove the stray 'L' from fields that do not support it

Example fix

// before
new CronExpression("0 0 0L * * ?");
// after
new CronExpression("0 0 0 L * ?"); // last day of month
Defensive patterns

Strategy: validation

Validate before calling

boolean validLOption(String[] fields) {
    // fields in Quartz order: sec min hour dom mon dow [year]
    boolean domL = fields[3].equals("L") || fields[3].equals("LW") || fields[3].matches("\\d+W");
    boolean dowL = fields[5].matches("[1-7]L|[A-Z]{3}L");
    return fields[0].matches("[0-9*/,-]+") && fields[1].matches("[0-9*/,-]+")
        && fields[2].matches("[0-9*/,-]+") && (fields[3].matches("[0-9*?/,-]+") || domL)
        && fields[4].matches("[A-Z0-9*?/,-]+") && (fields[5].matches("[0-9?*/,-]+|[A-Z?,/-]+") || dowL);
}

Try / catch

try {
    CronExpression cron = new CronExpression(expr);
} catch (ParseException e) {
    if (e.getMessage().startsWith("'L' option is not valid here")) {
        throw new ConfigurationException("'L' is only valid alone in day-of-month or as nL in day-of-week: " + expr, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Expressions using 'L' in wrong fields, e.g. "0 0 0L * * ?" (L after hour values), "0 0 L 1 * ?" reached through checkNext, or 'L' appended to month/second/minute values.

Common situations: Misunderstanding Quartz 'L' semantics; copy-pasting expressions from documentation for other cron dialects; typos where 'L' was meant for the day-of-month field.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

        int end = -1;
        int i = pos;

        if (i >= s.length()) {
            addToSet(val, end, -1, type);
            return i;
        }

        char c = s.charAt(pos);

        if (c == 'L') {
            if (type == DAY_OF_WEEK) {
                if (val < 1 || val > 7) {
                    throw new ParseException("Day-of-Week values must be between 1 and 7", -1);
                }
                lastdayOfWeek = true;
            } else {
                throw new ParseException("'L' option is not valid here. (pos=" + i + ")", i);
            }
            TreeSet<Integer> set = getSet(type);
            set.add(val);
            i++;
            return i;
        }

        if (c == 'W') {
            if (type == DAY_OF_MONTH) {
                nearestWeekday = true;
            } else {
                throw new ParseException("'W' option is not valid here. (pos=" + i + ")", i);
            }
            if (val > 31) {
                throw new ParseException(
                        "The 'W' option does not make sense with values larger than 31 (max number of days in a month)",
                        i);
            }

View on GitHub (pinned to d6d39ce1c6)