flowable/flowable-engine · error · FlowableIllegalArgumentException

Cannot find process definition with id " +…

Error message

Cannot find process definition with id " + (builder.hasNewProcessDefinitionId() ? builder.getNewProcessDefinitionId() : builder.getProcessDefinitionId())

What it means

ModifyProcessInstanceStartEventSubscriptionCmd.execute() resolves the (possibly latest) process definition for a start event subscription change. When the definition lookup returns null — neither the new process definition id nor the original one can be found — it throws FlowableIllegalArgumentException 'Cannot find process definition with id <id>'.

Solutions

  1. Verify the process definition id via repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult() before calling.
  2. Use the definition key and let Flowable resolve the latest version instead of a hard-coded version-specific id.
  3. If passing a newProcessDefinitionId, confirm it exists and is deployed for the same tenant.
  4. Catch FlowableIllegalArgumentException and fall back to the current latest definition.

Example fix

// before
migrationBuilder.modifyStartEventSubscription()
    .migrateToProcessDefinition(unknownDefId);
// after
ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
    .processDefinitionId(unknownDefId).singleResult();
if (def == null) {
    def = repositoryService.createProcessDefinitionQuery()
        .processDefinitionKey(key).latestVersion().singleResult();
}
migrationBuilder.modifyStartEventSubscription().migrateToProcessDefinition(def.getId());
Defensive patterns

Strategy: validation

Validate before calling

ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
    .processDefinitionId(targetDefId).singleResult();
if (def == null) {
    throw new IllegalArgumentException("Unknown process definition id: " + targetDefId);
}

Type guard

boolean definitionExists(String defId) {
    return defId != null && repositoryService.createProcessDefinitionQuery()
        .processDefinitionId(defId).count() > 0;
}

Try / catch

try {
    builder.migrateToProcessDefinition(defId);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().startsWith("Cannot find process definition")) {
        log.warn("Definition {} not found; using latest by key instead", defId);
    }
    throw e;
}

Prevention

When it happens

Trigger: Using the process instance migration/modification start-event subscription builder (e.g. migrationBuilder.modifyStartEventSubscription...) with a processDefinitionId that does not exist, was deleted, or refers to another engine's data.

Common situations: Stale ids after redeployment and cleanup of old process definitions; typo in definition id; pointing at a definition deployed to a different tenant/engine; referencing definitions removed by history/deployment cleanup jobs.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/ModifyProcessInstanceStartEventSubscriptionCmd.java:58

    protected final ProcessInstanceStartEventSubscriptionModificationBuilderImpl builder;

    public ModifyProcessInstanceStartEventSubscriptionCmd(ProcessInstanceStartEventSubscriptionModificationBuilderImpl builder) {
        this.builder = builder;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        ProcessDefinition newProcessDefinition;
        if (builder.hasNewProcessDefinitionId()) {
            newProcessDefinition = getProcessDefinitionById(builder.getNewProcessDefinitionId(), commandContext);
        } else {
            // no explicit process definition provided, so use latest one
            ProcessDefinition processDefinition = getProcessDefinitionById(builder.getProcessDefinitionId(), commandContext);
            newProcessDefinition = getLatestProcessDefinitionByKey(processDefinition.getKey(), processDefinition.getTenantId(), commandContext);
        }

        if (newProcessDefinition == null) {
            throw new FlowableIllegalArgumentException("Cannot find process definition with id " + (builder.hasNewProcessDefinitionId() ?
                builder.getNewProcessDefinitionId() :
                builder.getProcessDefinitionId()));
        }

        Process process = getProcess(newProcessDefinition.getId(), commandContext);

        List<StartEvent> startEvents = process.findFlowElementsOfType(StartEvent.class, false);
        for (StartEvent startEvent : startEvents) {
            // looking for a start event based on an event-registry event subscription
            EventRegistryEventDefinition eventDefinition = EventRegistryEventDefinitionUtil.findOn(startEvent);
            if (eventDefinition != null && StringUtils.isNotEmpty(eventDefinition.getEventDefinitionKey())) {
                // looking for a dynamic, manually subscribed behavior of the event-registry start event
                List<ExtensionElement> correlationConfiguration = startEvent.getExtensionElements().get(BpmnXMLConstants.START_EVENT_CORRELATION_CONFIGURATION);
                if (correlationConfiguration != null && correlationConfiguration.size() > 0 &&
                    BpmnXMLConstants.START_EVENT_CORRELATION_MANUAL.equals(correlationConfiguration.get(0).getElementText())) {

                    String eventDefinitionKey = eventDefinition.getEventDefinitionKey();
                    String correlationKey = null;

View on GitHub (pinned to d6d39ce1c6)