flowable/flowable-engine · error · FlowableIllegalArgumentException
Cannot parse duration
Error message
Cannot parse duration
What it means
Thrown by AdvancedCycleBusinessCalendar.resolveDuedate as FlowableIllegalArgumentException when any part of parsing the cycle/ISO duration description fails (TimeDuration, cron-like expression, or daylight-saving arithmetic) while computing the next due date for a timer. Any exception in the calculation is wrapped with this generic message.
Solutions
- Validate the timer definition string: it must be a valid ISO 8601 cycle (e.g. 'R3/PT10M' or 'R/ISO interval') or valid cron expression supported by the calendar.
- Test the exact duedate string with AdvancedCycleBusinessCalendar.resolveDuedate in a unit test to see the wrapped cause (getCause()).
- Fix common typos: use 'P'/'PT' prefixes correctly, valid repetition counts, and unambiguous ISO intervals.
- If using variable expressions in the timer, ensure they resolve to non-empty valid strings at runtime.
Example fix
// before <timeCycle>R/PT1H/2026-13-40T00:00:00Z</timeCycle> <!-- invalid date --> // after <timeCycle>R/PT1H/2026-12-31T00:00:00Z</timeCycle>
Defensive patterns
Strategy: validation
Validate before calling
boolean isValidCycle(String duedate) {
try { Duration.parse(duedate.startsWith("P") ? duedate : duedate.substring(duedate.indexOf('/') + 1)); return true; }
catch (DateTimeParseException e) { return false; }
} Try / catch
try {
Date due = calendar.resolveDuedate(duedateDescription);
} catch (FlowableIllegalArgumentException e) {
log.error("Invalid timer cycle '{}': {}", duedateDescription, e.getCause(), e);
throw new IllegalArgumentException("Fix BPMN timeCycle definition", e);
} Prevention
- Validate ISO 8601 cycle strings (Rn/PT.., ISO intervals) before deploying BPMN.
- Unit-test timer definitions with resolveDuedate and inspect getCause() on failure.
- Avoid mixing legacy 'R/...' legacy syntax with new ISO repetition syntax inconsistently.
- Ensure expression-based timers always resolve to non-empty valid strings.
When it happens
Trigger: A timer boundary/start event or job with a malformed duedateDescription: bad ISO 8601 duration/cycle (e.g. 'R/PT1H/x'), invalid cron-style fields, wrong ISO string segments, or an expression that the calendar's getValueFrom cannot extract.
Common situations: Typos in timer cycle definitions in BPMN XML; using legacy 'R/...' strings mixed with new ISO 8601 repetition syntax; expressions returning null/empty values; locale/timezone issues around DST transitions producing invalid dates.
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
- Activity needed for multi instance cannot bv found
- An end date can only be provided when rescheduling a timer…
- At most one non-null value can be provided for timeDate…
- Cannot parse array index:
- Cannot parse EL property
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/83e0dc618f788cd3.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/AdvancedCycleBusinessCalendar.java:116
// START is a legacy value that is no longer used, but may still exist in deployed job schedules
// Could be used in the future as a start date for a CRON job
// String startDate = getValueFrom("START", duedateDescription);
duedateDescription = removeValueFrom("VER", removeValueFrom("START", removeValueFrom("DSTZONE", duedateDescription))).trim();
try {
LOGGER.info("Base Due Date: {}", duedateDescription);
Date date = resolvers.get(version == null ? getDefaultScheduleVersion() : Integer.valueOf(version)).resolve(duedateDescription, clockReader,
timeZone == null ? clockReader.getCurrentTimeZone() : TimeZone.getTimeZone(timeZone));
LOGGER.info("Calculated Date: {}", date == null ? "Will Not Run Again" : date);
return date;
} catch (Exception e) {
throw new FlowableIllegalArgumentException("Cannot parse duration", e);
}
}
private String getValueFrom(String field, String duedateDescription) {
int fieldIndex = duedateDescription.indexOf(field + ":");
if (fieldIndex > -1) {
int nextWhiteSpace = duedateDescription.indexOf(' ', fieldIndex);
fieldIndex += field.length() + 1;
if (nextWhiteSpace > -1) {
return duedateDescription.substring(fieldIndex, nextWhiteSpace);
} else {
return duedateDescription.substring(fieldIndex);
}
}View on GitHub (pinned to d6d39ce1c6)