jeecgboot/JeecgBoot · error · ParseException
'W' option is not valid here. (pos=${i})
Error message
'W' option is not valid here. (pos=${i}) What it means
Thrown when the 'W' (nearest weekday) modifier appears in any cron field other than day-of-month. The 'W' character instructs the scheduler to fire on the closest weekday (Mon–Fri) to the given day number, and it is only meaningful for the day-of-month field. Using it in second, minute, hour, day-of-week, month, or year fields is a syntax error.
Source
Thrown at jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java:769
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) {
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);
nearestWeekdays.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 {
nthDayOfWeek = Integer.parseInt(s.substring(i));
if (nthDayOfWeek < 1 || nthDayOfWeek > 5) {
throw new Exception();
}View on GitHub (pinned to 96fb33f5ec)
Solutions
- Ensure the 'W' modifier appears only in the day-of-month field (the 4th field in a 6-field cron, or 3rd of 6 before year).
- Verify field count and ordering: seconds minutes hours day-of-month month day-of-week [year].
- Use '?' in the day-of-week field when specifying a day-of-month with 'W'.
Example fix
// before String cron = "0 0 0 ? * 15W"; // 'W' is in day-of-week position — wrong // after String cron = "0 0 0 15W * ?"; // 'W' in day-of-month position
Defensive patterns
Strategy: validation
Validate before calling
// Ensure 'W' only appears in the day-of-month field (field index 3)
String[] fields = cronExpr.split("\\s+");
for (int f = 0; f < fields.length; f++) {
if (fields[f].contains("W") && f != 3) {
throw new IllegalArgumentException("'W' is only valid in day-of-month field");
}
} Type guard
boolean isWOnlyInDayOfMonth(String cron) {
String[] fields = cron.trim().split("\\s+");
for (int f = 0; f < fields.length; f++) {
if (fields[f].contains("W") && f != 3) return false;
}
return true;
} Try / catch
try {
CronExpression cron = new CronExpression(expr);
} catch (ParseException e) {
if (e.getMessage().contains("'W' option is not valid here")) {
// 'W' was placed in a non-day-of-month field
}
throw e;
} Prevention
- Use 'W' only in the day-of-month field.
- Pair day-of-month 'W' with '?' in day-of-week.
- Verify field count and alignment before constructing the expression.
When it happens
Trigger: A cron expression containing 'W' after a numeric value where type != DAY_OF_MONTH — e.g., day-of-week field '5W', hour field '10W', or month field '3W'.
Common situations: Developer confuses day-of-week and day-of-month field positions; expression has an extra or missing field causing misalignment; copy-paste error placing 'W' in the wrong field.
Related errors
- Day-of-Week values must be between 1 and 7
- 'L' option is not valid here. (pos=${i})
- The 'W' option does not make sense with values larger than 3
- '#' option is not valid here. (pos=${i})
- Unexpected character '${c}' after '/'
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/3470c51099805d93.
Report an issue: GitHub.