Activiti/Activiti · error · ParseException

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

Error message

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

What it means

checkNext throws this ParseException when the 'L' special character is used in a cron field other than day-of-week. The 'L' option is only legal as a suffix on the day-of-week field (e.g. '5L' = last Friday of month) or alone in day-of-month ('L' = last day); elsewhere it is a syntax error. Note the exception message uses the outer variable i (often 0 here) rather than the actual position, so the reported pos can be misleading.

Solutions

  1. Move the 'L' to a field where it is valid: use 'L' alone in day-of-month for 'last day of month', or '<n>L' in day-of-week for 'last <n> weekday of month'.
  2. Remove the stray 'L' from the invalid field and keep the plain numeric value.
  3. Validate with CronExpression.isValidExpression before storing the cron string in configuration.

Example fix

// before
String cron = "0 9L * * * ?"; // throws: 'L' option is not valid here
// after
String cron = "0 0 9 L * ?"; // 09:00 on the last day of the month
Defensive patterns

Strategy: try-catch

Validate before calling

if (!org.activiti.engine.impl.calendar.CronExpression.isValidExpression(cronString)) {
    throw new IllegalArgumentException("Invalid cron expression: " + cronString);
}

Try / catch

try {
    new CronExpression(cronString);
} catch (java.text.ParseException e) {
    if (e.getMessage().contains("'L' option is not valid")) {
        // 'L' is only valid in day-of-month (alone) or day-of-week (as '<n>L');
        // report the offending field to the user
    }
}

Prevention

When it happens

Trigger: A cron expression containing 'L' in a field where it is not allowed, e.g. '0 0 L * * *'? no wait, day-of-month 'L' is handled elsewhere; concrete trigger is 'L' following a value parsed by checkNext in a non-DAY_OF_WEEK field, e.g. hours field '9L' ('0 9L * * *') or minute field '5L', or 'L' suffix on a month value.

Common situations: Copy-pasting cron strings between dialects where L is accepted in day-of-month but written into the wrong field; typos like '5L' in minute fields; generated expressions appending L after a generic numeric field; misunderstanding Quartz's field-specific L semantics.

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 Activiti/Activiti@56435b1a97 (2026-09-09). Data as JSON: /api/errors/5b51d20e7eaaad8b. Report an issue: GitHub.

Appendix: source

Thrown at activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/calendar/CronExpression.java:567

    }

    protected int checkNext(int pos, String s, int val, int type) throws ParseException {
        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(Integer.valueOf(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
            );
            TreeSet<Integer> set = getSet(type);

View on GitHub (pinned to 56435b1a97)