flowable/flowable-engine · error · FlowableException

Timer expression

Error message

Timer expression 

What it means

When rescheduling a timer, the command evaluates the new date expression. If the resolved value is not a java.util.Date (neither a literal Date nor a parseable expression result), it throws FlowableException saying the timer expression did not resolve to a Date.

Solutions

  1. Ensure the referenced variable is a java.util.Date before rescheduling
  2. Pass a Date object directly instead of a string/expression
  3. Use an ISO-8601 parseable string if a string must be supplied
  4. Log and inspect the exception's 'pe' cause by evaluating the expression manually in a test

Example fix

// before
cmmnRuntimeService.setTimerJobDueDate(jobId, "${dueDateString}"); // variable is a String
// after
Date due = new SimpleDateFormat("yyyy-MM-dd").parse("2026-10-01");
cmmnRuntimeService.setTimerJobDueDate(jobId, due);
Defensive patterns

Strategy: validation

Validate before calling

Object v = caseVariables.get("dueDateVar");
if (!(v instanceof java.util.Date)) throw new IllegalArgumentException("timer var must be java.util.Date");

Type guard

boolean isResolvableDate(Object v) { return v instanceof java.util.Date; }

Try / catch

try { runtimeService.setTimerJobDueDate(jobId, due); } catch (FlowableException e) { log.error("Timer expression did not resolve to Date", e); }

Prevention

When it happens

Trigger: Passing a new due date as a String expression like '${someDate}' whose variable is missing or not a Date; passing a formatted string not parseable as ISO date; passing an unsupported type (Long, Instant) through the expression.

Common situations: Setting a process/case variable used by the timer expression to a String instead of Date; typos in date format; using java.time types that Flowable's CMMN timer expression resolver does not accept.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/RescheduleTimerJobCmd.java:120

                isRepeating = true;

            } else {

                // Try to parse as ISO8601 first
                try {
                    timerDueDate = DateUtil.parseDate(newDateValue);
                } catch (Exception e) { }

                // Try to parse as cron expression
                try {
                    timerDueDate = businessCalendarManager.getBusinessCalendar(CycleBusinessCalendar.NAME).resolveDuedate(newDateValue);
                    isRepeating = true;

                } catch (Exception pe) { }
            }
            
            if (timerDueDate == null) {
                throw new FlowableException("Timer expression '" + newDateValue + "' did not resolve to java.util.Date for " + planItemInstance);
            }
        }
        
        CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
        JobServiceConfiguration jobServiceConfiguration = cmmnEngineConfiguration.getJobServiceConfiguration();
        
        TimerJobEntity newTimer = timerJobService.createTimerJob();
        newTimer.setJobType(timerJob.getJobType());
        newTimer.setJobHandlerType(timerJob.getJobHandlerType());
        newTimer.setExclusive(true);
        newTimer.setRetries(jobServiceConfiguration.getAsyncExecutorNumberOfRetries());
        newTimer.setDuedate(timerDueDate);
        newTimer.setScopeDefinitionId(timerJob.getScopeDefinitionId());
        newTimer.setScopeId(timerJob.getScopeId());
        newTimer.setSubScopeId(timerJob.getSubScopeId());
        newTimer.setCategory(timerJob.getCategory());
        newTimer.setScopeType(timerJob.getScopeType());
        newTimer.setElementId(timerJob.getElementId());

View on GitHub (pinned to d6d39ce1c6)