jeecgboot/JeecgBoot · error · ParseException
Offset from last day must be <= {MAX_LAST_DAY_OFFSET}
Error message
Offset from last day must be <= {MAX_LAST_DAY_OFFSET} What it means
For DAY_OF_MONTH the 'L-N' syntax means 'N days before the last day of month' (e.g. L-3 = third-to-last day). The parser caps the offset at MAX_LAST_DAY_OFFSET (=30); an offset greater than 30 is rejected because no month has more than 31 days so a larger backward offset is meaningless. The thrown message interpolates the constant so it reads '<= 30'.
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:685
} 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;
}
if (s.length() > i) {
c = s.charAt(i);
if (c == 'W') {
nearestWeekday = true;
i++;
}
}
}
if (nearestWeekday) {
nearestWeekdays.add(dom);
} else {
daysOfMonth.add(dom);
}
}
return i;View on GitHub (pinned to 96fb33f5ec)
Solutions
- Keep the L-offset between 0 and 30 (L-0 or just L = last day).
- If you need an earlier date, use an explicit day number (e.g. '15') instead of a large L-offset.
- Clamp computed offsets to the 0-30 range before assembling the cron string.
Example fix
// before - offset beyond the 30-day cap String cron = "0 0 0 L-40 * ?"; // Offset from last day must be <= 30 // after - valid offset, or explicit day String cron = "0 0 0 L-5 * ?"; // or a concrete day number String cron = "0 0 0 1 * ?";
Defensive patterns
Strategy: validation
Validate before calling
private static final int MAX_LAST_DAY_OFFSET = 30;
// Validate an 'L-N' day-of-month token before assembling the cron string.
public static String validateLastDayOffset(String domField) {
if (domField == null || !domField.startsWith("L-")) return null;
try {
int offset = Integer.parseInt(domField.substring(2));
if (offset < 0 || offset > MAX_LAST_DAY_OFFSET) {
return "L-offset must be 0.." + MAX_LAST_DAY_OFFSET + ", got " + offset;
}
} catch (NumberFormatException ex) {
return "L-offset must be an integer: " + domField;
}
return null;
} Type guard
public static boolean isValidLastDayOffsetToken(String token) {
if (token == null) return false;
if (token.equals("L") || token.matches("LW?") || token.matches("LW")) return true;
java.util.regex.Matcher m = java.util.regex.Pattern.compile("^L-(\\d+)W?$").matcher(token);
if (!m.matches()) return false;
int off = Integer.parseInt(m.group(1));
return off >= 0 && off <= 30;
} Try / catch
try {
new CronExpression(expr);
} catch (ParseException e) {
if (e.getMessage().startsWith("Offset from last day")) {
return "The L-offset must be <= 30. Use an explicit day number for earlier dates. " + e.getMessage();
}
throw e;
} Prevention
- Clamp L-offsets to 0-30 when generating 'L-N' tokens.
- Prefer explicit day numbers for dates more than 30 days before month end.
- Unit-test generated L-offset expressions against the parser.
When it happens
Trigger: A day-of-month like 'L-31', 'L-40', or a computed 'L-' + largeNumber. Also negative or garbage that parseInt turns into a large value. Index i+1 points at the digit start.
Common situations: Programmatic offset that is unbounded; confusion about whether the offset is 0- or 1-based; trying to express 'end of quarter' with a fixed large offset.
Related errors
- Increment >= 31 : {incr}
- Illegal cron expression format ({e})
- Invalid Month value: '{sub}'
- Invalid Day-of-Week value: '{sub}'
- A numeric value between 1 and 5 must follow the '#' option
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/9b703f9b87a1b1b3.
Report an issue: GitHub.