flowable/flowable-engine · error · ActivitiException

No execution context active and event is not related to an…

Error message

No execution context active and event is not related to an execution. No compensation event can be thrown.

What it means

ErrorThrowingEventListener (for compensation/error events) needs an execution to propagate the error through. If there is no active command context execution and the dispatched event carries no executionId, propagation is impossible and it throws ActivitiException.

Solutions

  1. Attach the error-throwing listener only to execution-scoped event types that carry an executionId
  2. Dispatch the listener within a command context (e.g. from process logic rather than external threads)
  3. Check event types in the listener registration and remove ones unrelated to executions
  4. If the event legitimately has no execution, use a different listener mechanism that doesn't need an execution

Example fix

// before
<flowable:eventListener events="ENGINE_CREATED" delegateExpression="${errorThrowingListener}"/>
// after
<flowable:eventListener events="ACTIVITY_COMPLETED" delegateExpression="${errorThrowingListener}"/>
Defensive patterns

Strategy: validation

Validate before calling

// only register error-throwing listeners for execution-bound events
java.util.Set<String> EXECUTION_EVENTS = java.util.Set.of("ACTIVITY_STARTED","ACTIVITY_COMPLETED","ACTIVITY_SIGNALED","PROCESS_STARTED","PROCESS_COMPLETED");
if (!EXECUTION_EVENTS.contains(eventType)) throw new IllegalArgumentException("error-throwing listener needs execution-bound event, got " + eventType);

Try / catch

try {
    runtimeService.startProcessInstanceByKey("myProcess");
} catch (org.activiti.engine.ActivitiException e) {
    if (e.getMessage() != null && e.getMessage().contains("No execution context active")) {
        logger.error("Error-throwing listener fired without execution context", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A global engine event listener configured to throw an error event fires for an event unrelated to any execution (e.g. engine-level event) or outside an active command context, so neither Context.getExecutionEntityManager lookup nor engineEvent.getExecutionId() yields an execution.

Common situations: Registering an error-throwing listener on engine-wide events (e.g. CONFIGURATION_*, job/async events without execution); dispatching events from a non-command thread; listener used on events that occur before/after process execution exists.

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/9fce442a5c426b10. Report an issue: GitHub.

Appendix: source

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

public class ErrorThrowingEventListener extends BaseDelegateEventListener {

    protected String errorCode;

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

            if (Context.isExecutionContextActive()) {
                execution = Context.getExecutionContext().getExecution();
            } else if (engineEvent.getExecutionId() != null) {
                // Get the execution based on the event's execution ID instead
                execution = Context.getCommandContext().getExecutionEntityManager().findExecutionById(engineEvent.getExecutionId());
            }

            if (execution == null) {
                throw new ActivitiException("No execution context active and event is not related to an execution. No compensation event can be thrown.");
            }

            try {
                ErrorPropagation.propagateError(errorCode, execution);
            } catch (Exception e) {
                throw new ActivitiException("Error while propagating error-event", e);
            }
        }
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    @Override
    public boolean isFailOnException() {
        return true;
    }

View on GitHub (pinned to d6d39ce1c6)