jeecgboot/JeecgBoot · 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

'L' means 'last' (last day of month, or last weekday). It is only meaningful for DAY_OF_MONTH and DAY_OF_WEEK. Because field types are numbered SECOND=0, MINUTE=1, HOUR=2, DAY_OF_MONTH=3, the guard 'type < DAY_OF_MONTH' rejects 'L' in the seconds, minutes or hours fields. Using 'L' there 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: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 96fb33f5ec)

Solutions

  1. Use 'L' only in the day-of-month field (e.g. '0 0 0 L * ?' = last day of month at 00:00) or day-of-week field ('0 0 0 ? * L' = Saturday).
  2. For 'last second/minute/hour' there is no Quartz equivalent - express it numerically (59, 59, 23).
  3. Validate that 'L' appears only in dom (field 4) or dow (field 6) positions.

Example fix

// before - 'L' in the hour field
String cron = "0 0 L * * ?";  // 'L' not expected in seconds, minutes or hours fields

// after - 23 for last hour, L reserved for day-of-month
String cron = "0 0 23 * * ?";
// or last day of month
String cron = "0 0 0 L * ?";
Defensive patterns

Strategy: validation

Validate before calling

// 'L' is legal only in dom (index 3) or dow (index 5).
public static String validateLastModifierPlacement(String expr) {
    String[] f = expr.trim().split("\\s+");
    for (int i = 0; i < f.length && i < 6; i++) {
        if (f[i].contains("L") && i != 3 && i != 5) {
            return "'L' is only allowed in day-of-month or day-of-week, found in field " + (i + 1);
        }
    }
    return null;
}

Type guard

public static boolean lastModifierOnlyInDayFields(String[] fields) {
    for (int i = 0; i < fields.length && i < 6; i++) {
        if (fields[i].contains("L") && i != 3 && i != 5) return false;
    }
    return true;
}

Try / catch

try {
    new CronExpression(expr);
} catch (ParseException e) {
    if (e.getMessage().contains("not expected in seconds")) {
        return "'L' is for day fields only. Use 59/59/23 for last second/minute/hour. " + e.getMessage();
    }
    throw e;
}

Prevention

When it happens

Trigger: An 'L' in an early field: 'L * * * * ?' (SECOND), '0 L * * * ?' (MINUTE), '0 0 L * * ?' is valid (HOUR would be invalid too: '0 0 L * * ?' -> HOUR='L' triggers since HOUR=2 < 3). The 'L' for hours is sometimes confused with a 'last hour' concept that Quartz does not support.

Common situations: Assuming 'L' means 'last X' for any unit; copy/paste of an 'L' template into the wrong field; UI that lets users pick 'last' without scoping it to day fields.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/e1f38602233ec360. Report an issue: GitHub.