flowable/flowable-engine · error · FlowableIllegalArgumentException

Due date expression does not resolve to a Date, Instant, Loc

Error message

Due date expression does not resolve to a Date, Instant, LocalDate, LocalDateTime or Date string: + beforeContext.getDueDate()

What it means

The user task's flowable:dueDate expression resolved to an object whose type the engine cannot turn into a task due date. Only Date, Date-time (java.util.Date), String parseable as a date, Instant, LocalDate and LocalDateTime are accepted. A FlowableIllegalArgumentException is thrown when the expression evaluates to some other type.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java:274

                    if (StringUtils.isNotEmpty(userTask.getBusinessCalendarName())) {
                        businessCalendarName = expressionManager.createExpression(userTask.getBusinessCalendarName()).getValue(execution).toString();
                    } else {
                        businessCalendarName = DueDateBusinessCalendar.NAME;
                    }

                    BusinessCalendar businessCalendar = processEngineConfiguration.getBusinessCalendarManager()
                            .getBusinessCalendar(businessCalendarName);
                    task.setDueDate(businessCalendar.resolveDuedate((String) dueDate));
                } else if (dueDate instanceof Instant) {
                    task.setDueDate(Date.from((Instant) dueDate));
                } else if (dueDate instanceof LocalDate) {
                    Date localDueDate = Date.from(((LocalDate) dueDate).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
                    task.setDueDate(localDueDate);
                } else if (dueDate instanceof LocalDateTime) {
                    Date localDueDate = Date.from(((LocalDateTime) dueDate).atZone(ZoneId.systemDefault()).toInstant());
                    task.setDueDate(localDueDate);
                } else {
                    throw new FlowableIllegalArgumentException("Due date expression does not resolve to a Date, Instant, LocalDate, LocalDateTime or Date string: " + beforeContext.getDueDate());
                }
            }
        }
    }

    protected void handlePriority(CreateUserTaskBeforeContext beforeContext, ExpressionManager expressionManager, TaskEntity task, DelegateExecution execution,
            String activeTaskPriority) {
        if (StringUtils.isNotEmpty(beforeContext.getPriority())) {
            final Object priority = expressionManager.createExpression(beforeContext.getPriority()).getValue(execution);
            if (priority != null) {
                if (priority instanceof String) {
                    try {
                        task.setPriority(Integer.valueOf((String) priority));
                    } catch (NumberFormatException e) {
                        throw new FlowableIllegalArgumentException("Priority does not resolve to a number: " + priority, e);
                    }
                } else if (priority instanceof Number) {
                    task.setPriority(((Number) priority).intValue());

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Change the expression/bean to return java.util.Date, Instant, LocalDate, LocalDateTime, or a date-String in an accepted format
  2. Convert ZonedDateTime/OffsetDateTime via toLocalDateTime() or Date.from(...) before returning it
  3. Set the process variable to the correct type before reaching the user task
  4. Fix the ISO date format of the String if returning text
  5. Wrap the logic in a delegate that normalizes the value

Example fix

// before
public ZonedDateTime getDueDate() { return ZonedDateTime.now().plusDays(2); }
// after
public Date getDueDate() { return Date.from(ZonedDateTime.now().plusDays(2).toInstant()); }
Defensive patterns

Strategy: validation

Validate before calling

Object d = dueDateExpr.getValue(execution);
List<Class<?>> ok = List.of(Date.class, Instant.class, LocalDate.class, LocalDateTime.class, String.class);
if (d != null && ok.stream().noneMatch(c -> c.isInstance(d))) {
    throw new IllegalArgumentException("dueDate type not supported: " + d.getClass());
}

Type guard

boolean isValidDueDate(Object v) {
    return v == null || v instanceof Date || v instanceof Instant
        || v instanceof LocalDate || v instanceof LocalDateTime || v instanceof String;
}

Try / catch

try {
    completeTask(taskId, vars);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().startsWith("Due date expression")) {
        // fix variable type and retry
    }
}

Prevention

When it happens

Trigger: flowable:dueDate expression like ${someVar} or ${bean.compute()} returning e.g. Integer, ZonedDateTime, OffsetDateTime, String in an unparseable format, or an unsupported object.

Common situations: Using ZonedDateTime/OffsetDateTime which are NOT supported (only LocalDate/LocalDateTime/Instant); expression returning a formatted String the date parser cannot read; passing a timestamp long from a variable; Spring bean method returning the wrong type.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/d536cf8ffafcd406. Report an issue: GitHub.