flowable/flowable-engine · error · ActivitiIllegalArgumentException

Cannot throw process-instance scoped message, since the…

Error message

Cannot throw process-instance scoped message, since the dispatched event is not part of an ongoing process instance

What it means

Thrown as ActivitiIllegalArgumentException when a MessageThrowingEventListener tries to throw a process-instance-scoped message but the dispatched FlowableEngineEvent has a null processInstanceId. The engine cannot resolve a process instance scope to look up the message event subscription, so the throw is rejected up front.

Solutions

  1. Register the message-throwing listener only for events that occur within a process instance execution (e.g. ACTIVITY_COMPLETED, TASK_COMPLETED), not engine-level events.
  2. Check the FlowableEngineEvent.getProcessInstanceId() in your own listener logic before delegating to the message-throwing listener.
  3. If the message should be global rather than per-instance, use a non-process-instance-scoped message mechanism instead.
  4. Review the process definition extension elements and remove the listener from events that fire outside a process instance.

Example fix

// before: listener bound to a global event
<activiti:eventListener events="ENGINE_CREATED" eventType="message-throwing" messageName="myMessage"/>

// after: bind to an in-execution event
<activiti:eventListener events="ACTIVITY_COMPLETED" eventType="message-throwing" messageName="myMessage"/>
Defensive patterns

Strategy: validation

Validate before calling

if (event instanceof FlowableEngineEvent) {
    if (((FlowableEngineEvent) event).getProcessInstanceId() == null) {
        throw new IllegalStateException("Message-throwing listener requires an event inside a process instance");
    }
}

Type guard

boolean isExecutionScoped(FlowableEvent event) {
    return event instanceof FlowableEngineEvent
        && ((FlowableEngineEvent) event).getProcessInstanceId() != null;
}

Try / catch

try {
    dispatchEvent(event);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("not part of an ongoing process instance")) {
        logger.warn("Skipped message throw: event not execution-scoped");
    } else { throw e; }
}

Prevention

When it happens

Trigger: onEvent is invoked with an engine event whose getProcessInstanceId() returns null — e.g. a process-engine-level event (deployment, engine start/stop) registered for a message-throwing listener, while the listener's message is scoped to a process instance.

Common situations: Registering a message-throwing event listener on global/engine-level events in the process engine configuration; events dispatched during deployment or engine bootstrap that have no process instance attached; misconfigured <activiti:eventListener> entries in the process definition.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/MessageThrowingEventListener.java:44

/**
 * An {@link FlowableEventListener} that throws a message event when an event is dispatched to it. Sends the message to the execution the event was fired from. If the execution is not subscribed to a
 * message, the process-instance is checked.
 * 
 * @author Frederik Heremans
 * 
 */
public class MessageThrowingEventListener extends BaseDelegateEventListener {

    protected String messageName;
    protected Class<?> entityClass;

    @Override
    public void onEvent(FlowableEvent event) {
        if (isValidEvent(event) && event instanceof FlowableEngineEvent) {
            FlowableEngineEvent engineEvent = (FlowableEngineEvent) event;

            if (engineEvent.getProcessInstanceId() == null) {
                throw new ActivitiIllegalArgumentException(
                        "Cannot throw process-instance scoped message, since the dispatched event is not part of an ongoing process instance");
            }

            CommandContext commandContext = Context.getCommandContext();
            List<EventSubscriptionEntity> subscriptionEntities = commandContext.getEventSubscriptionEntityManager()
                    .findEventSubscriptionsByNameAndExecution(MessageEventHandler.EVENT_HANDLER_TYPE, messageName, engineEvent.getExecutionId());

            // Revert to messaging the process instance
            if (subscriptionEntities.isEmpty() && engineEvent.getProcessInstanceId() != null &&
                    !engineEvent.getExecutionId().equals(engineEvent.getProcessInstanceId())) {

                subscriptionEntities = commandContext.getEventSubscriptionEntityManager()
                        .findEventSubscriptionsByNameAndExecution(MessageEventHandler.EVENT_HANDLER_TYPE, messageName, engineEvent.getProcessInstanceId());
            }

            for (EventSubscriptionEntity signalEventSubscriptionEntity : subscriptionEntities) {
                signalEventSubscriptionEntity.eventReceived(null, false);
            }

View on GitHub (pinned to d6d39ce1c6)