flowable/flowable-engine · error · ActivitiException

Cannot deploy process definition

Error message

Cannot deploy process definition '%s': there multiple message event subscriptions for the message with name '%s'.

What it means

When deploying, every message start event in the process creates a message event subscription. If a single process definition declares multiple start events subscribed to the same message name, the deployment is rejected because subscriptions would be ambiguous.

Solutions

  1. Give each message start event a distinct message name (or distinct message element)
  2. Remove the duplicate message start event
  3. Use one start event with multiple conditional paths instead of multiple identical message starts

Example fix

<!-- before -->
<message id="msgOrder" name="orderMessage"/>
<startEvent id="s1"><messageEventDefinition messageRef="msgOrder"/></startEvent>
<startEvent id="s2"><messageEventDefinition messageRef="msgOrder"/></startEvent>
<!-- after -->
<message id="msgOrder" name="orderMessage"/>
<message id="msgCancel" name="cancelMessage"/>
<startEvent id="s1"><messageEventDefinition messageRef="msgOrder"/></startEvent>
<startEvent id="s2"><messageEventDefinition messageRef="msgCancel"/></startEvent>
Defensive patterns

Strategy: validation

Validate before calling

Set<String> names = new HashSet<>();
for (String msgStart : collectMessageStartEventNames(processXml)) {
    if (!names.add(msgStart)) throw new IllegalStateException("Duplicate message start name: " + msgStart);
}

Try / catch

try {
    repositoryService.createDeployment().addClasspathResource(model).deploy();
} catch (org.activiti.engine.ActivitiException e) {
    if (e.getMessage().contains("multiple message event subscriptions")) {
        // fix the model: make each message start event name unique
    }
}

Prevention

When it happens

Trigger: deploy -> addMessageEventSubscriptions when two or more message start events within one process definition (same resource) reference the same message name.

Common situations: Copy-pasting a message start event in the BPMN designer and forgetting to change the message name; merging process models that each used the same message name.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/deployer/BpmnDeployer.java:407

            }

        }
    }

    @SuppressWarnings("unchecked")
    protected void addMessageEventSubscriptions(ProcessDefinitionEntity processDefinition) {
        CommandContext commandContext = Context.getCommandContext();
        List<EventSubscriptionDeclaration> eventDefinitions = (List<EventSubscriptionDeclaration>) processDefinition.getProperty(BpmnParse.PROPERTYNAME_EVENT_SUBSCRIPTION_DECLARATION);
        if (eventDefinitions != null) {

            Set<String> messageNames = new HashSet<>();
            for (EventSubscriptionDeclaration eventDefinition : eventDefinitions) {
                if ("message".equals(eventDefinition.getEventType()) && eventDefinition.isStartEvent()) {

                    if (!messageNames.contains(eventDefinition.getEventName())) {
                        messageNames.add(eventDefinition.getEventName());
                    } else {
                        throw new ActivitiException("Cannot deploy process definition '" + processDefinition.getResourceName()
                                + "': there multiple message event subscriptions for the message with name '" + eventDefinition.getEventName() + "'.");
                    }

                    // look for subscriptions for the same name in db:
                    List<EventSubscriptionEntity> subscriptionsForSameMessageName = commandContext.getEventSubscriptionEntityManager()
                            .findEventSubscriptionsByName(MessageEventHandler.EVENT_HANDLER_TYPE,
                                    eventDefinition.getEventName(), processDefinition.getTenantId());
                    // also look for subscriptions created in the session:
                    List<MessageEventSubscriptionEntity> cachedSubscriptions = commandContext
                            .getDbSqlSession()
                            .findInCache(MessageEventSubscriptionEntity.class);
                    for (MessageEventSubscriptionEntity cachedSubscription : cachedSubscriptions) {
                        if (eventDefinition.getEventName().equals(cachedSubscription.getEventName())
                                && !subscriptionsForSameMessageName.contains(cachedSubscription)) {
                            subscriptionsForSameMessageName.add(cachedSubscription);
                        }
                    }
                    // remove subscriptions deleted in the same command

View on GitHub (pinned to d6d39ce1c6)