flowable/flowable-engine · error · ActivitiException
Cannot deploy process definition
Error message
Cannot deploy process definition '%s': there already is a message event subscription for the message with name '%s'.
What it means
A message name must be globally unique for message start events: the deployer checks the event subscription table (ACT_RU_EVENT_SUB) for existing start-event subscriptions (those with no processInstanceId) using the same message name. If one exists, the new deployment is rejected to avoid nondeterministic message correlation.
Solutions
- Delete the old process definition deployment that holds the conflicting message start subscription
- Use a unique message name for the new process definition
- Clean up orphaned rows in ACT_RU_EVENT_SUB if they belong to removed definitions
Defensive patterns
Strategy: validation
Validate before calling
List<EventSubscription> subs = runtimeService.createEventSubscriptionQuery()
.eventName(messageName).eventType("message").list();
boolean conflict = subs.stream().anyMatch(s -> s.getProcessInstanceId() == null); Try / catch
try {
repositoryService.createDeployment().addClasspathResource(model).deploy();
} catch (org.activiti.engine.ActivitiException e) {
if (e.getMessage().contains("already is a message event subscription")) {
// delete the old deployment or rename the message
}
} Prevention
- Reserve globally unique message names per process definition
- Delete old deployments that hold message start subscriptions before redeploying with the same name
- Don't share one test database across environments deploying conflicting models
When it happens
Trigger: deploy -> addMessageEventSubscriptions when the new process definition's message start event name matches an existing start-event subscription in the database, typically created by a previously deployed process definition.
Common situations: Deploying a second, differently-keyed process that uses the same message name as an already deployed process; test environments sharing one database; failing to undeploy/delete an old definition that still holds the subscription.
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/09922794c847be29.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/deployer/BpmnDeployer.java:434
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
subscriptionsForSameMessageName = commandContext
.getDbSqlSession()
.pruneDeletedEntities(subscriptionsForSameMessageName);
for (EventSubscriptionEntity eventSubscriptionEntity : subscriptionsForSameMessageName) {
// throw exception only if there's already a subscription as start event
if (eventSubscriptionEntity.getProcessInstanceId() == null || eventSubscriptionEntity.getProcessInstanceId().isEmpty()) {
// the event subscription has no instance-id, so it's a message start event
throw new ActivitiException("Cannot deploy process definition '" + processDefinition.getResourceName()
+ "': there already is a message event subscription for the message with name '" + eventDefinition.getEventName() + "'.");
}
}
MessageEventSubscriptionEntity newSubscription = new MessageEventSubscriptionEntity();
newSubscription.setEventName(eventDefinition.getEventName());
newSubscription.setActivityId(eventDefinition.getActivityId());
newSubscription.setConfiguration(processDefinition.getId());
newSubscription.setProcessDefinitionId(processDefinition.getId());
if (processDefinition.getTenantId() != null) {
newSubscription.setTenantId(processDefinition.getTenantId());
}
newSubscription.insert();
}
}
}View on GitHub (pinned to d6d39ce1c6)