flowable/flowable-engine · error · FlowableException
Due date could not be determined for timer job
Error message
Due date could not be determined for timer job ${dueDateString} for ${variableContainer} What it means
After parsing the timer's due date value and/or resolving it via the business calendar, the dueDate is still null. TimerUtil throws this FlowableException because a timer job cannot be created without a computable due date, even though some raw date string was present.
Solutions
- Fix or replace the BusinessCalendar so resolveDuedate never returns null for valid input (return now/next-open instead).
- Verify the dueDateString format matches what the selected business calendar can parse.
- Check the calendarName reference on the timerEventDefinition points to a registered calendar in the BusinessCalendarManager.
- Log/inspect dueDateString at runtime and unit test the calendar with the exact production values.
Example fix
// before
class CustomCalendar implements BusinessCalendar {
public Date resolveDuedate(String d, ...) { return parseOrNull(d); }
}
// after
public Date resolveDuedate(String d, ...) {
Date parsed = parseOrNull(d);
return parsed != null ? parsed : new Date(); // never return null
} Defensive patterns
Strategy: validation
Validate before calling
Date due = businessCalendar.resolveDuedate(dueDateString);
if (due == null) throw new IllegalStateException("Business calendar returned null duedate for: " + dueDateString); Try / catch
try { /* create timer */ } catch (FlowableException e) { if (e.getMessage().startsWith("Due date could not be determined")) log.error("Calendar/timer misconfig: {}", e.getMessage()); else throw e; } Prevention
- Unit-test custom BusinessCalendar implementations to never return null
- Verify calendarName refs exist in the BusinessCalendarManager config
- Validate due-date string formats against the active calendar
When it happens
Trigger: timeDate/timeCycle/timeDuration resolve to a value (or dueDateString is produced) but the BusinessCalendar.resolveDuedate returns null or the value fails conversion so duedate remains null at the final check in createTimerEntity.
Common situations: Business calendar (e.g. 'businessCalendarName' ref) configured so the given date falls outside working hours and resolves to null; custom BusinessCalendar implementations returning null; malformed cycle expressions handled leniently upstream; custom calendars swapped in via config.
Related errors
- Could not find matching FlowElement for activityId " +…
- Could not find process definition needed for timer start…
- Error reading json value " + configuration + " for job " +…
- Error reading json value " + configuration + " for " + job
- exception during timer execution for " + job
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/65c7a50ee406af28.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TimerUtil.java:221
timer.setJobHandlerType(jobHandlerType);
timer.setJobHandlerConfiguration(jobHandlerConfig);
timer.setExclusive(true);
timer.setRetries(processEngineConfiguration.getAsyncExecutorNumberOfRetries());
timer.setDuedate(duedate);
String jobCategoryElementText = resolveJobCategoryText(currentFlowElement);
if (jobCategoryElementText != null) {
Expression categoryExpression = processEngineConfiguration.getExpressionManager().createExpression(jobCategoryElementText);
Object categoryValue = categoryExpression.getValue(variableContainer);
if (categoryValue != null) {
timer.setCategory(categoryValue.toString());
}
}
} else {
StringBuilder sb = new StringBuilder("Due date could not be determined for timer job ").append(dueDateString);
sb.append(" for ").append(variableContainer);
throw new FlowableException(sb.toString());
}
if (StringUtils.isNotEmpty(timerEventDefinition.getTimeCycle())) {
// See ACT-1427: A boundary timer with a cancelActivity='true', doesn't need to repeat itself
boolean repeat = !isInterruptingTimer;
// ACT-1951: intermediate catching timer events shouldn't repeat according to spec
if (currentFlowElement instanceof IntermediateCatchEvent) {
repeat = false;
}
if (repeat) {
String prepared = prepareRepeat(dueDateString);
timer.setRepeat(prepared);
}
}
View on GitHub (pinned to d6d39ce1c6)