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

  1. 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.
  2. Test the exact duedate string with AdvancedCycleBusinessCalendar.resolveDuedate in a unit test to see the wrapped cause (getCause()).
  3. Fix common typos: use 'P'/'PT' prefixes correctly, valid repetition counts, and unambiguous ISO intervals.
  4. 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

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


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)