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
- Give each message start event a distinct message name (or distinct message element)
- Remove the duplicate message start event
- 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
- Model each message start event with a distinct message element/name
- Review merged process models for duplicated start events
- Validate BPMN with a schema/designer check before deployment
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
- Cannot deploy process definition
- Cannot deploy process definition
- Cannot start process instance by message: subscription to…
- Cannot throw process-instance scoped message, since the…
- Cannot throw process-instance scoped message, since the…
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 commandView on GitHub (pinned to d6d39ce1c6)