flowable/flowable-engine · error · FlowableException

failedJobRetryTimeCycle has wrong format:" +…

Error message

failedJobRetryTimeCycle has wrong format:" + failedJobRetryTimeCycleValue + " for execution " + executionEntity

What it means

JobRetryCmd parses the failedJobRetryTimeCycle value (e.g. 'R5/PT1M') to compute job retry decrements. If parsing/applying the retry cycle throws any Exception, it is wrapped as FlowableException 'failedJobRetryTimeCycle has wrong format:<value> for execution <execution>', with the original parse failure as cause.

Solutions

  1. Fix the failedJobRetryTimeCycle value to valid ISO-8601 repetition format, e.g. 'R3/PT10M' (3 retries every 10 minutes).
  2. Check the exception cause in the logs to see exactly which parser rejected the value.
  3. If the value comes from a placeholder/property, confirm it resolves to a literal value before deployment.
  4. Remove the cycle temporarily to let the job fail normally while you correct configuration.

Example fix

// before
<flowable:failedJobRetryTimeCycle>${retryCycle}</flowable:failedJobRetryTimeCycle>
// after
<flowable:failedJobRetryTimeCycle>R5/PT7M</flowable:failedJobRetryTimeCycle>
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern RETRY_CYCLE =
    Pattern.compile("^R\\d+/PT?\\d+[HMS]$");
if (!RETRY_CYCLE.matcher(failedJobRetryTimeCycle).matches()) {
    throw new IllegalArgumentException("Invalid retry time cycle: " + failedJobRetryTimeCycle);
}

Type guard

boolean isValidRetryTimeCycle(String v) {
    return v != null && v.matches("^R\\d+/PT?\\d+[HMS]$");
}

Try / catch

try {
    managementService.moveJobToDeadLetterJob(jobId);
} catch (FlowableException e) {
    if (e.getMessage().contains("failedJobRetryTimeCycle has wrong format")) {
        log.error("Fix failedJobRetryTimeCycle value; cause: {}", e.getCause(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: An async job failed and the execution/element has a failedJobRetryTimeCycle configured (in BPMN extension elements or process engine configuration) whose value is not a valid ISO-8601 repetition interval, e.g. '5', 'R/PT10M', 'PTx', or containing typos.

Common situations: Typo in the time cycle string in the BPMN XML; property placeholder not resolved so a raw '${retryCycle}' ends up in the value; copying examples with wrong interval syntax; configuration injected from environment variables with bad values.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/JobRetryCmd.java:144

                if (jobRetries <= 1 || isUnrecoverableException()) {
                    newJobEntity = jobService.moveJobToDeadLetterJob(job);
                } else {
                    newJobEntity = timerJobService.moveJobToTimerJob(job);
                }

                newJobEntity.setDuedate(durationHelper.getDateAfter());

                if (job.getExceptionMessage() == null) { // is it the first exception
                    LOGGER.debug("Applying JobRetryStrategy '{}' the first time for job {} with {} retries", failedJobRetryTimeCycleValue, job.getId(), durationHelper.getTimes());

                } else {
                    LOGGER.debug("Decrementing retries of JobRetryStrategy '{}' for job {}", failedJobRetryTimeCycleValue, job.getId());
                }

                newJobEntity.setRetries(jobRetries - 1);

            } catch (Exception e) {
                throw new FlowableException("failedJobRetryTimeCycle has wrong format:" + failedJobRetryTimeCycleValue + " for execution " + executionEntity, e);
            }
        }

        if (exception != null) {
            newJobEntity.setExceptionMessage(exception.getMessage());
            newJobEntity.setExceptionStacktrace(getExceptionStacktrace());
        }

        // Dispatch both an update and a retry-decrement event
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();
        if (eventDispatcher != null && eventDispatcher.isEnabled()) {
            eventDispatcher.dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_UPDATED, newJobEntity),
                    processEngineConfiguration.getEngineCfgKey());
            eventDispatcher.dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.JOB_RETRIES_DECREMENTED, newJobEntity),
                    processEngineConfiguration.getEngineCfgKey());
        }

View on GitHub (pinned to d6d39ce1c6)