jeecgboot/JeecgBoot · error · ParseException

'?' can only be specified for Day-of-Month or Day-of-Week.

Error message

'?' can only be specified for Day-of-Month or Day-of-Week.

What it means

'?' (NO_SPEC) is semantically allowed only in the day-of-month or day-of-week fields, because those two fields are mutually exclusive in Quartz. If the parser encounters '?' while parsing SECOND, MINUTE, HOUR, or MONTH (type != DAY_OF_WEEK and != DAY_OF_MONTH), it throws this. It enforces the Quartz rule that you specify '?' in one day field to let the other be set.

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:620

                        "Illegal characters for this position: '" + sub + "'",
                        i);
            }
            if (eval != -1) {
                incr = 1;
            }
            addToSet(sval, eval, incr, type);
            return (i + 3);
        }

        if (c == '?') {
            i++;
            if ((i + 1) < s.length()
                    && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) {
                throw new ParseException("Illegal character after '?': "
                        + s.charAt(i), i);
            }
            if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) {
                throw new ParseException(
                        "'?' can only be specified for Day-of-Month or Day-of-Week.",
                        i);
            }
            if (type == DAY_OF_WEEK) {
                if (!daysOfMonth.isEmpty() && daysOfMonth.last() == NO_SPEC_INT) {
                    throw new ParseException(
                            "'?' can only be specified for Day-of-Month -OR- Day-of-Week.",
                            i);
                }
            }

            addToSet(NO_SPEC_INT, -1, 0, type);
            return i;
        }

        if (c == '*' || c == '/') {
            if (c == '*' && (i + 1) >= s.length()) {
                addToSet(ALL_SPEC_INT, -1, incr, type);

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Use '*' (not '?') for 'every value' in SECOND/MINUTE/HOUR/MONTH.
  2. Reserve '?' exclusively for the dom-or-dow field you are leaving unspecified.
  3. Validate that '?' appears only in field positions 4 (dom) or 6 (dow) of the expression.

Example fix

// before - '?' in the minute field
String cron = "0 ? 0 * * ?";  // Illegal: ? in MINUTE

// after - '*' for every minute, '?' only in a day field
String cron = "0 * 0 * * ?";
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

try {
    new CronExpression(expr);
} catch (ParseException e) {
    if (e.getMessage().contains("Day-of-Month or Day-of-Week")) {
        return "Use '*' (not '?') in second/minute/hour/month; reserve '?' for the day fields. " + e.getMessage();
    }
    throw e;
}

Prevention

When it happens

Trigger: A '?' in a non-day field: '0 ? 0 * * *' (MINUTE='?'), '? * * * * *' (SECOND), '0 0 0 * ? *' is fine but '0 0 0 * 1 ? *' with MONTH or '0 ? 0 * * ?' is not. Common when a developer copies the dom/dow '?' pattern into every field.

Common situations: Misunderstanding '?' as a generic wildcard; putting '?' in seconds/minutes to mean 'every'; templates that fill unused fields with '?'.

Related errors


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