flowable/flowable-engine · error · FlowableIllegalArgumentException

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

Error message

Due date expression does not resolve to a Date, Instant, LocalDate, LocalDateTime or Date string: 

What it means

The due date attribute expression resolved to an object of an unsupported type. Flowable accepts java.util.Date, Instant, LocalDate, LocalDateTime, or a String parseable as a date; anything else (Calendar, ZonedDateTime, custom type) is rejected with FlowableIllegalArgumentException enumerating the accepted types.

Solutions

  1. Normalize the variable to java.util.Date or LocalDateTime before the plan item executes.
  2. If it is ZonedDateTime/OffsetDateTime, convert: Date.from(zdt.toInstant()) when setting the variable.
  3. If it is a String, use a format Flowable can parse (e.g. ISO-8601 yyyy-MM-dd or full date-time) or provide a java.util.Date.
  4. Catch FlowableIllegalArgumentException and log beforeContext.getDueDate() plus the value's class to identify the offending type.

Example fix

// before
execution.setVariable("dueDate", ZonedDateTime.now().plusDays(2));
// after
execution.setVariable("dueDate", Date.from(ZonedDateTime.now().plusDays(2).toInstant()));
Defensive patterns

Strategy: type-guard

Validate before calling

Object d = variableScope.getVariable("dueDate");
boolean ok = d == null || d instanceof java.util.Date || d instanceof java.time.Instant
    || d instanceof java.time.LocalDate || d instanceof java.time.LocalDateTime;
if (!ok) throw new IllegalArgumentException("dueDate must be Date, Instant, LocalDate or LocalDateTime, got " + (d == null ? "null" : d.getClass()));

Type guard

boolean isValidDueDate(Object v) { return v == null || v instanceof java.util.Date || v instanceof java.time.Instant || v instanceof java.time.LocalDate || v instanceof java.time.LocalDateTime; }

Try / catch

try {
    // execute human task
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().startsWith("Due date expression")) {
        log.error("Unsupported due date type: {}", e.getMessage());
    }
}

Prevention

When it happens

Trigger: HumanTaskActivityBehavior.execute -> handleDueDate, when the dueDate expression returns a non-null object failing all accepted instanceof branches (Date, Instant, LocalDate, LocalDateTime, String).

Common situations: Variable is a ZonedDateTime/OffsetDateTime or java.sql.Timestamp subclass branch not handled; expression returns a Date-formatted display String with a locale-specific pattern the parser cannot read; JS/ Groovy evaluation returning a wrapped type.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/HumanTaskActivityBehavior.java:349

                    taskEntity.setDueDate((Date) dueDate);

                } else if (dueDate instanceof String dueDateString) {
                    Date resolvedDuedate = CommandContextUtil.getCmmnEngineConfiguration(commandContext).getBusinessCalendarManager()
                            .getBusinessCalendar(DueDateBusinessCalendar.NAME)
                            .resolveDuedate(dueDateString);
                    taskEntity.setDueDate(resolvedDuedate);

                } else if (dueDate instanceof Instant) {
                    taskEntity.setDueDate(Date.from((Instant) dueDate));

                } else if (dueDate instanceof LocalDate) {
                    taskEntity.setDueDate(Date.from(((LocalDate) dueDate).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));

                }  else if (dueDate instanceof LocalDateTime) {
                    taskEntity.setDueDate(Date.from(((LocalDateTime) dueDate).atZone(ZoneId.systemDefault()).toInstant()));

                } else {
                    throw new FlowableIllegalArgumentException("Due date expression does not resolve to a Date, Instant, LocalDate, LocalDateTime or Date string: " + beforeContext.getDueDate());
                }
            }
        }
    }

    protected void handleCategory(PlanItemInstanceEntity planItemInstanceEntity, ExpressionManager expressionManager,
            TaskEntity taskEntity, CreateHumanTaskBeforeContext beforeContext, MigrationContext migrationContext) {
        
        String categoryStringValue = null;
        if (migrationContext != null && migrationContext.getCategory() != null) {
            categoryStringValue = migrationContext.getCategory();
            
        } else if (StringUtils.isNotEmpty(beforeContext.getCategory())) {
            categoryStringValue = beforeContext.getCategory();
        }
        
        if (StringUtils.isNotEmpty(categoryStringValue)) {
            final Object category = expressionManager.createExpression(categoryStringValue).getValue(planItemInstanceEntity);

View on GitHub (pinned to d6d39ce1c6)