jeecgboot/JeecgBoot · error · ParseException

Support for specifying multiple "nth" days is not…

Error message

Support for specifying multiple "nth" days is not implemented.

What it means

Thrown by CronExpression's parser when the day-of-week field contains more than one '#' character — e.g., 'FRI#2,FRI#4' or '6#1,6#3'. The '#' modifier specifies the 'nth occurrence' of a day in a month (e.g., '6#3' = third Friday). Quartz does not support multiple nth-day specifiers in a single expression. The check detects a second '#' after the first one in the field.

Solutions

  1. Split into multiple CronTriggers: one for '6#1' (first Friday) and another for '6#3' (third Friday), both targeting the same job.
  2. If the schedule can be expressed as 'every N weeks', consider using a different scheduling strategy (e.g., a simple periodic trigger with date filtering).
  3. Use '6#1' alone if only one nth-occurrence is needed: '0 0 12 ? * 6#1'.

Example fix

// before: multiple # specifiers in one expression — invalid
String cron = "0 0 12 ? * 6#1,6#3";
CronExpression expr = new CronExpression(cron);

// after: two separate triggers
CronTrigger firstFriday = TriggerBuilder.newTrigger()
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 ? * 6#1"))
    .build();
CronTrigger thirdFriday = TriggerBuilder.newTrigger()
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 ? * 6#3"))
    .build();
scheduler.scheduleJob(jobDetail, firstFriday);
scheduler.scheduleJob(jobDetail, thirdFriday);
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate day-of-week field for multiple # specifiers
public void validateDayOfWeekField(String cronExpression) {
    String[] fields = cronExpression.trim().split("\\s+");
    if (fields.length >= 6) {
        String dayOfWeek = fields[5];
        int hashCount = dayOfWeek.length() - dayOfWeek.replace("#", "").length();
        if (hashCount > 1) {
            throw new IllegalArgumentException(
                "Cannot specify multiple '#' nth-day modifiers: " + dayOfWeek);
        }
    }
}

Type guard

// Check if day-of-week field has at most one # specifier
public boolean hasValidNthDaySpecifier(String dow) {
    if (dow == null || dow.isEmpty()) return true;
    int hashCount = dow.length() - dow.replace("#", "").length();
    return hashCount <= 1;
}

Try / catch

try {
    CronExpression cron = new CronExpression(expression);
} catch (ParseException e) {
    if (e.getMessage().contains("nth")) {
        throw new IllegalArgumentException(
            "Multiple '#' specifiers are not supported. Split into separate triggers.", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Cron expression like '0 0 12 ? * 6#1,6#3' trying to run on the first and third Friday of each month. Expression like '0 0 6 ? * 1#1,1#3' for first and third Sunday. Any comma-separated day-of-week value containing two or more '#' characters.

Common situations: Scheduling bi-weekly or specific-week-of-month jobs that need multiple nth-occurrence rules. Misunderstanding that '#' can only appear once per expression. Building dynamic cron strings that concatenate multiple '#'-based rules.

Related errors


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

Appendix: 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:494

            int exprOn = SECOND;

            StringTokenizer exprsTok = new StringTokenizer(expression, " \t",
                    false);

            if(exprsTok.countTokens() > 7) {
                throw new ParseException("Invalid expression has too many terms: " + expression, -1);
            }

            while (exprsTok.hasMoreTokens() && exprOn <= YEAR) {
                String expr = exprsTok.nextToken().trim();

                // throw an exception if L is used with other days of the week
                if(exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1  && expr.contains(",")) {
                    throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1);
                }
                if(exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') +1) != -1) {
                    throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1);
                }

                StringTokenizer vTok = new StringTokenizer(expr, ",");
                while (vTok.hasMoreTokens()) {
                    String v = vTok.nextToken();
                    storeExpressionVals(0, v, exprOn);
                }

                exprOn++;
            }

            if (exprOn <= DAY_OF_WEEK) {
                throw new ParseException("Unexpected end of expression.",
                        expression.length());
            }

            if (exprOn <= YEAR) {
                storeExpressionVals(0, "*", YEAR);

View on GitHub (pinned to 96fb33f5ec)