flowable/flowable-engine · error · ActivitiException
Timer ' ' was not configured with a valid duration/time…
Error message
Timer '${activityId}' was not configured with a valid duration/time, either hand in a java.util.Date or a String in format 'yyyy-MM-dd'T'hh:mm:ss' What it means
TimerJobEntity.restoreExtraData evaluates the timer's end-date expression when re-creating a timer (e.g. after restart or when scheduling repeating timers). The expression must evaluate to a java.util.Date or a String parseable by the business calendar; any other type makes the engine throw this ActivitiException naming the activity. It protects the job store from an unparseable due date.
Solutions
- Make the expression return a java.util.Date or an ISO-8601 'yyyy-MM-dd'T'hh:mm:ss' String
- Convert the variable at process start (store as Date or formatted String) instead of at timer evaluation time
- Fix the expression in the BPMN XML (e.g. ${endDate} → ${endDateAsString} backed by a correctly typed variable)
- Check for type changes after engine/version migration and re-deploy with corrected models
Example fix
// before: variable is a timestamp long
runtimeService.startProcessInstanceByKey("p", vars); // vars: endDate = 1727000000L
// after
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
vars.put("endDate", fmt.format(new Date(1727000000L * 1000)));
runtimeService.startProcessInstanceByKey("p", vars); Defensive patterns
Strategy: validation
Validate before calling
Object v = vars.get("endDate");
boolean ok = v instanceof java.util.Date || v instanceof String; // String must be ISO yyyy-MM-dd'T'HH:mm:ss Type guard
boolean isValidTimerValue(Object v) {
return v instanceof java.util.Date || v instanceof String;
} Prevention
- Store timer inputs as Date or ISO-8601 strings only
- Validate expression result types when authoring BPMN models
- Re-check timer expressions after engine upgrades/migrations
When it happens
Trigger: A boundary/intermediate timer's timeDate/timeDuration/timeCycle endDate expression evaluates to a type other than Date or String (e.g. Integer, Long, or a custom object) when the timer job is restored or scheduled by execute/scheduleNewTimer.
Common situations: Process variable passed into a timer endDate expression has the wrong type (number instead of ISO date string or Date); expression returns a Joda/Java-8 type the engine doesn't recognize; Activiti 5→Flowable migration where variable types changed; expression misconfigured in BPMN XML.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- Timer ' ' in was not configured with a valid duration/time…
- Could not find matching FlowElement for activityId " +…
- duedate is null
- Timer ' ' was not configured with a valid duration/time
- Timer expression ' ' did not resolve to java.util.Date…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/950a8c662993b46d.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/TimerJobEntity.java:231
.getBusinessCalendar(getBusinessCalendarName(TimerEventHandler.geCalendarNameFromConfiguration(jobHandlerConfiguration)));
VariableScope executionEntity = null;
if (executionId != null) {
executionEntity = commandContext.getExecutionEntityManager().findExecutionById(executionId);
}
if (executionEntity == null) {
executionEntity = NoExecutionVariableScope.getSharedInstance();
}
if (endDateExpression != null) {
Object endDateValue = endDateExpression.getValue(executionEntity);
if (endDateValue instanceof String) {
endDateString = (String) endDateValue;
} else if (endDateValue instanceof Date) {
endDate = (Date) endDateValue;
} else {
throw new ActivitiException("Timer '" + ((ExecutionEntity) executionEntity).getActivityId()
+ "' was not configured with a valid duration/time, either hand in a java.util.Date or a String in format 'yyyy-MM-dd'T'hh:mm:ss'");
}
if (endDate == null) {
endDate = businessCalendar.resolveEndDate(endDateString);
}
}
}
}
if (processDefinitionId != null) {
ProcessDefinition def = Context.getProcessEngineConfiguration().getRepositoryService().getProcessDefinition(processDefinitionId);
maxIterations = checkStartEventDefinitions(def, embededActivityId);
if (maxIterations <= 1) {
maxIterations = checkBoundaryEventsDefinitions(def, embededActivityId);
}
} else {
maxIterations = 1;View on GitHub (pinned to d6d39ce1c6)