flowable/flowable-engine · error · FlowableIllegalArgumentException

The process definition with id ${processDefinitionId} has mo

Error message

The process definition with id ${processDefinitionId} has more than one event-registry start events based on manually registered subscriptions, which is currently not supported.

What it means

When starting a process instance via an event-registry start event with manual correlation configuration, Flowable registers a start-event subscription per process definition. The engine supports at most ONE manually registered event-registry start event per process definition; RegisterProcessInstanceStartEventSubscriptionCmd.execute throws FlowableIllegalArgumentException when it encounters a second such start event while a subscription is already registered.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/RegisterProcessInstanceStartEventSubscriptionCmd.java:71

    @Override
    public EventSubscription execute(CommandContext commandContext) {
        ProcessDefinition processDefinition = getLatestProcessDefinitionByKey(builder.getProcessDefinitionKey(), builder.getTenantId(), commandContext);
        Process process = getProcess(processDefinition.getId(), commandContext);

        EventSubscription eventSubscription = null;
        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())) {

                    // currently, only one event-registry start event is supported for manual subscriptions
                    if (eventSubscription != null) {
                        throw new FlowableIllegalArgumentException("The process definition with id " + processDefinition.getId()
                            + " has more than one event-registry start events based on manually registered subscriptions, which is currently not supported.");
                    }

                    String eventDefinitionKey = eventDefinition.getEventDefinitionKey();
                    String correlationKey = generateCorrelationConfiguration(eventDefinitionKey, builder.getTenantId(),
                            builder.getCorrelationParameterValues(), commandContext);

                    eventSubscription = insertEventRegistryEvent(eventDefinitionKey, builder.isDoNotUpdateToLatestVersionAutomatically(), startEvent, processDefinition,
                        correlationKey, commandContext);
                }
            }
        }

        if (eventSubscription == null) {
            throw new FlowableIllegalArgumentException("The process definition with id '" + processDefinition.getId()
                + "' does not have an event-registry based start event with a manual subscription behavior.");
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Keep at most one manually-correlated event-registry start event per process definition; split the second trigger into a separate process definition
  2. Change the second start event's correlation configuration from 'manual' to automatic/default correlation (remove the flowable:startEventCorrelationConfiguration extension or set it to a supported value)
  3. Restructure the model so one start event fans out via the event registry (e.g. catch the other messages after process start with intermediate event-registry catch events)

Example fix

<!-- before: two manually-correlated start events in one definition -->
<startEvent id="startA"><extensionElements>
  <flowable:startEventCorrelationConfiguration>manual</flowable:startEventCorrelationConfiguration>
</extensionElements></startEvent>
<startEvent id="startB"><extensionElements>
  <flowable:startEventCorrelationConfiguration>manual</flowable:startEventCorrelationConfiguration>
</extensionElements></startEvent>
<!-- after: single manual start event; other trigger modeled as intermediate catch event -->
<startEvent id="startA"><extensionElements>
  <flowable:startEventCorrelationConfiguration>manual</flowable:startEventCorrelationConfiguration>
</extensionElements></startEvent>
<intermediateCatchEvent id="catchB"><extensionElements>
  <flowable:eventRegistryEventDefinition eventDefinitionKey="msgB"/>
</extensionElements></intermediateCatchEvent>
Defensive patterns

Strategy: validation

Validate before calling

long manualStartEvents = model.getBpmnModel().getMainProcess().getFlowElements().stream()
    .filter(StartEvent.class::isInstance).map(StartEvent.class::cast)
    .filter(se -> se.getExtensionElements()
        .getOrDefault("startEventCorrelationConfiguration", Collections.emptyList())
        .stream().anyMatch(e -> "manual".equals(e.getElementText())))
    .count();
if (manualStartEvents > 1) throw new IllegalStateException("At most one manual event-registry start event allowed");

Type guard

boolean hasSingleManualStartEvent(BpmnModel model) {
    long n = model.getMainProcess().getFlowElements().stream()
        .filter(StartEvent.class::isInstance)
        .map(StartEvent.class::cast)
        .filter(se -> se.getExtensionElements()
            .getOrDefault("startEventCorrelationConfiguration", Collections.emptyList())
            .stream().anyMatch(e -> "manual".equals(e.getElementText())))
        .count();
    return n <= 1;
}

Try / catch

try {
    runtimeService.createProcessInstanceBuilder().start();
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("more than one event-registry start events")) {
        // fix the BPMN model: keep one manual start event, redeploy
    }
    throw e;
}

Prevention

When it happens

Trigger: Deploying/starting a process definition whose BPMN model contains two or more event-registry start events whose <extensionElements> include flowable:startEventCorrelationConfiguration with value 'manual'; during execution of RegisterProcessInstanceStartEventSubscriptionCmd the loop finds eventSubscription already set for a second qualifying start event.

Common situations: Modeling multiple message/start events with manual correlation in one process definition (e.g. two different business messages that may both start the instance); copying a start event with correlation configuration to add a second trigger; upgrading Flowable and hitting a previously-tolerated model shape.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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