flowable/flowable-engine · error · ParseException

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

Error message

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

What it means

Parse-time guard in CronExpression.checkNext: the 'W' (nearest weekday) option was used in a field other than day-of-month (it is only valid there), so the expression is rejected at the given position.

Solutions

  1. Use 'nW' only in the day-of-month field, e.g. "0 0 0 15W * ?"
  2. For nearest-weekday-like behavior in day-of-week, pick an explicit weekday value instead
  3. Remove the 'W' from unsupported fields

Example fix

// before
new CronExpression("0 0 0 ? * 5W");
// after
new CronExpression("0 0 0 15W * ?"); // nearest weekday to the 15th
Defensive patterns

Strategy: validation

Validate before calling

boolean validWOption(String[] fields) {
    return fields[3] != null && fields[3].matches("\\d{1,2}W");
}

Try / catch

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

Prevention

When it happens

Trigger: Expressions like "0 0 0 ? * 5W" (W in day-of-week) or "0 0 0 15W * ?" reached via checkNext after hour fields; 'W' appended to month or weekday values.

Common situations: Confusing 'W' semantics across cron dialects (some Unix crons reject W entirely; Quartz/Flowable only allow it in day-of-month); typos.

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/13db37e7d63e8101. Report an issue: GitHub.

Appendix: source

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

            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);
            }
            TreeSet<Integer> set = getSet(type);
            set.add(val);
            i++;
            return i;
        }

        if (c == '#') {
            if (type != DAY_OF_WEEK) {
                throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i);
            }
            i++;
            try {

View on GitHub (pinned to d6d39ce1c6)