xuxueli/xxl-job · error · ParseException
'L' not expected in seconds, minutes or hours fields.
Error message
'L' not expected in seconds, minutes or hours fields.
What it means
The 'L' (last) modifier is only valid in the Day-of-Month and Day-of-Week fields. It means 'last day of the month' or 'last weekday of the month'. This error fires when 'L' appears in the seconds, minutes, or hours field (type < DAY_OF_MONTH, i.e., type 0, 1, or 2).
Source
Thrown at xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java:670
}
incr = getNumericValue(s, i);
i++;
if (incr > 10) {
i++;
}
checkIncrementRange(incr, type, i);
} else {
incr = 1;
}
addToSet(ALL_SPEC_INT, -1, incr, type);
return i;
} else if (c == 'L') {
if(type < DAY_OF_MONTH)
throw new ParseException("'L' not expected in seconds, minutes or hours fields.", i);
i++;
if (type == DAY_OF_WEEK) {
addToSet(7, 7, 0, type);
}
if (type == DAY_OF_MONTH) {
int dom = LAST_DAY_OFFSET_END;
boolean nearestWeekday = false;
if (s.length() > i) {
c = s.charAt(i);
if (c == '-') {
ValueSet vs = getValue(0, s, i + 1);
int offset = vs.value;
if (offset > MAX_LAST_DAY_OFFSET)
throw new ParseException("Offset from last day must be <= " + MAX_LAST_DAY_OFFSET, i + 1);
dom -= offset;
i = vs.pos;
}View on GitHub (pinned to e74c784f68)
Solutions
- Remove the 'L' from the seconds/minutes/hours field; use a plain number or '*'.
- Move the 'L' logic to the day-of-month or day-of-week field where it is valid (e.g., '0 0 0 L * ?').
- Review the Quartz cron field reference to confirm where 'L' is permitted.
Example fix
// before "0 0 8L * * ?" // after "0 8 0 L * ?"
Defensive patterns
Strategy: validation
Validate before calling
// 'L' may only appear in field index 3 (day-of-month) or 5 (day-of-week)
String[] parts = cron.trim().split("\\s+");
for (int idx = 0; idx < parts.length; idx++) {
if (parts[idx].contains("L") && idx != 3 && idx != 5) {
throw new IllegalArgumentException("'L' is not valid in field " + idx + ": " + parts[idx]);
}
} Type guard
boolean isLInValidField(String[] parts) {
return (parts[0] == null || !parts[0].contains("L"))
&& (parts[1] == null || !parts[1].contains("L"))
&& (parts.length < 3 || !parts[2].contains("L")); Try / catch
try {
new CronExpression(cron);
} catch (ParseException e) {
if (e.getMessage().contains("'L' not expected")) {
// move 'L' to day-of-month or day-of-week
}
} Prevention
- Remember 'L' only applies to the two day fields.
- Document the valid scope of each cron modifier in your project's cron reference.
- Add a pre-parse validation layer for user-entered cron strings.
When it happens
Trigger: A cron expression such as '0 0 8L * * ?' where 'L' appears in the hour field, or '0 0L * * * ?' in the minute field. The check at line 669 tests type < DAY_OF_MONTH (3).
Common situations: Misunderstanding the scope of the 'L' modifier, or a cron-generation tool that applies 'L' to the wrong field index. Developers familiar with non-Quartz cron may not expect 'L' to be field-restricted.
Related errors
- '?' can only be specified for Day-of-Month -OR- Day-of-Week.
- Offset from last day must be <= {}
- Day-of-Week values must be between 1 and 7
- 'L' option is not valid here. (pos={})
- 'W' option is not valid here. (pos={})
AI-assisted analysis of xuxueli/xxl-job@e74c784f68 (2026-08-14).
Data as JSON: /api/errors/e2b4f000d2ff11e6.
Report an issue: GitHub.