flowable/flowable-engine · error · PvmException

already taking a transition

Error message

already taking a transition

What it means

A PvmException indicating ExecutionImpl.take(transition) was called on an execution that already holds a transition — i.e. it is already moving between activities. The PVM forbids double take() to prevent corrupting the execution's transition state. This is an internal state-guard, so hitting it usually signals a bug or invalid concurrent use.

Solutions

  1. Remove duplicate take() calls in custom behavior/listener code
  2. Check for re-entrancy: ensure listeners don't call take() during TRANSITION_NOTIFY_LISTENER_* operations
  3. Synchronize access if multiple threads signal the same execution
  4. Verify custom gateway behaviors only call take()/takeAll() once per execution

Example fix

// before
public void notify(DelegateExecution exec) {
  exec.take(exec.getActivity().getOutgoingFlows().get(0)); // engine already taking
}
// after
public void notify(DelegateExecution exec) {
  // just record state; let the engine take the transition
  exec.setVariable("notified", true);
}
Defensive patterns

Strategy: validation

Validate before calling

// guard custom code that might take a transition
if (((ExecutionImpl) execution).getTransition() != null) {
  throw new IllegalStateException("execution is already transitioning");
}

Prevention

When it happens

Trigger: Calling take(transition) twice on the same ExecutionImpl without the transition having been consumed (e.g. a custom behavior or listener calls take() while the engine is already performing a transition); concurrent threads signalling/taking the same execution.

Common situations: Custom ExecutionListeners on transition end calling execution.take(); behaviors like parallel gateways implemented incorrectly calling takeAll/take re-entrantly; async listeners racing on the same execution instance.

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/275008d1cab1ddb4. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/pvm/runtime/ExecutionImpl.java:587

        try {
            activityBehavior.signal(this, signalName, signalData);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new PvmException("couldn't process signal '" + signalName + "' on activity '" + activity.getId() + "': " + e.getMessage(), e);
        }
    }

    @Override
    public void take(PvmTransition transition, boolean fireActivityCompletedEvent) {
        // No event firing on executionlevel impl
        take(transition);
    }

    @Override
    public void take(PvmTransition transition) {
        if (this.transition != null) {
            throw new PvmException("already taking a transition");
        }
        if (transition == null) {
            throw new PvmException("transition is null");
        }
        setTransition((TransitionImpl) transition);
        performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_END);
    }

    @Override
    public void executeActivity(PvmActivity activity) {
        setActivity((ActivityImpl) activity);
        performOperation(AtomicOperation.ACTIVITY_START);
    }

    @Override
    public List<ActivityExecution> findInactiveConcurrentExecutions(PvmActivity activity) {
        List<ActivityExecution> inactiveConcurrentExecutionsInActivity = new ArrayList<>();
        List<ActivityExecution> otherConcurrentExecutions = new ArrayList<>();

View on GitHub (pinned to d6d39ce1c6)