apache/dolphinscheduler · error · IllegalArgumentException

Cannot parse the expression:

Error message

Cannot parse the expression: 

What it means

TimePlaceholderUtils.formatTimeExpression formats a time expression like $[add_months(yyyyMMdd,12*N)] against a given Date. It throws IllegalArgumentException('Cannot parse the expression: <expr>, date is null') when the supplied Date is null, because no baseline date exists to shift or format. (An empty expression with ignoreInvalidExpression=false throws the sibling 'Cannot format the date' error.)

Source

Thrown at dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtils.java:273

            return true;
        } else if (ADD_STRING.equals(peek) && (ADD_STRING.equals(cur) || SUBTRACT_STRING.equals(cur))) {
            return true;
        } else {
            return SUBTRACT_STRING.equals(peek) && (ADD_STRING.equals(cur) || SUBTRACT_STRING.equals(cur));
        }

    }

    /**
     * Format time expression with given date, the date cannot be null.
     * <p> If the expression is not a time expression, return the original expression.
     *
     */
    public static String formatTimeExpression(final String timeExpression, final Date date,
                                              final boolean ignoreInvalidExpression) {
        // After N years: $[add_months(yyyyMMdd,12*N)], the first N months: $[add_months(yyyyMMdd,-N)], etc
        if (date == null) {
            throw new IllegalArgumentException("Cannot parse the expression: " + timeExpression + ", date is null");
        }
        if (StringUtils.isEmpty(timeExpression)) {
            if (ignoreInvalidExpression) {
                return timeExpression;
            }
            throw new IllegalArgumentException("Cannot format the date" + date + " with null timeExpression");
        }
        try {
            if (timeExpression.startsWith(TIMESTAMP)) {
                return calculateTimeStamp(timeExpression, date);
            }
            if (timeExpression.startsWith(YEAR_WEEK)) {
                return calculateYearWeek(timeExpression, date);
            }
            return calcTimeExpression(timeExpression, date);
        } catch (Exception e) {
            if (ignoreInvalidExpression) {
                return timeExpression;

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Ensure the baseline date is computed before substitution (e.g. derive from schedule fire time via DateUtils) and never pass null.
  2. Guard the caller: if date == null, default to the workflow's scheduled time or now() depending on business semantics.
  3. For dependent tasks, verify the upstream task's finish time exists — it feeds the date used here.
  4. Catch IllegalArgumentException around formatTimeExpression only when ignoreInvalidExpression semantics are intended; otherwise let it fail loudly.
  5. Check the expression string too: an empty expression triggers the related error; validate non-empty before calling with ignoreInvalidExpression=false.

Example fix

// before
String result = TimePlaceholderUtils.formatTimeExpression(expr, null, false);
// after
Date base = scheduleFireTime != null ? scheduleFireTime : new Date();
String result = TimePlaceholderUtils.formatTimeExpression(expr, base, false);
Defensive patterns

Strategy: type-guard

Validate before calling

if (date == null) { date = scheduleFireTime != null ? scheduleFireTime : new Date(); }
if (timeExpression == null || timeExpression.isEmpty()) { throw new IllegalArgumentException("empty time expression"); }

Type guard

boolean canFormat(String expr, Date d) { return d != null && expr != null && !expr.isEmpty(); }

Try / catch

try { out = TimePlaceholderUtils.formatTimeExpression(expr, baseDate, false); } catch (IllegalArgumentException e) { log.error("time expression failed: {}", expr, e); throw new TaskException("time placeholder substitution failed", e); }

Prevention

When it happens

Trigger: Calling formatTimeExpression(timeExpression, null, false) — e.g. the scheduled/dependent fire time was not computed before placeholder substitution; a caller passes a null Date from a failed date calculation or from a parameter that was never set.

Common situations: Complement/dependent processing where the base schedule date is missing; calling the utility directly in custom plugins with an unset Date variable; a workflow triggered outside schedule context so the fire time is null.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/2ecafa86a7e0d012. Report an issue: GitHub.