flowable/flowable-engine · error · PvmException

transition is null

Error message

transition is null

What it means

A straightforward argument-validation PvmException: ExecutionImpl.take(transition) was invoked with a null PvmTransition. The engine requires an explicit outgoing transition to move the execution forward. Thrown before any state is mutated, so the execution remains unchanged.

Solutions

  1. Null-check the transition before calling take() and throw a descriptive error
  2. Verify the process definition actually contains the outgoing sequence flow being selected
  3. Fix transition-selection logic (match by flow id/name) to fall back to a default flow
  4. If building the model programmatically, ensure the TransitionImpl was added to the activity before use

Example fix

// before
PvmTransition t = activity.getOutgoingFlows().get(0);
execution.take(t); // NPE / PvmException if none
// after
List<PvmTransition> flows = activity.getOutgoingFlows();
if (flows.isEmpty()) throw new ActivitiException("no outgoing flow for " + activity.getId());
execution.take(flows.get(0));
Defensive patterns

Strategy: validation

Validate before calling

PvmTransition t = activity.getOutgoingFlows().stream()
    .filter(f -> name.equals(f.getId())).findFirst().orElse(null);
if (t == null) throw new ActivitiException("no outgoing flow named " + name);
execution.take(t);

Type guard

boolean hasOutgoing(PvmActivity a) { return a != null && !a.getOutgoingFlows().isEmpty(); }

Try / catch

try {
  execution.take(t);
} catch (PvmException e) {
  // transition was null — fix transition selection
}

Prevention

When it happens

Trigger: Calling execution.take(null) directly from custom code or a custom ActivityBehavior; computing outgoing transitions dynamically (e.g. getOutgoingFlows().get(i)) when the collection is empty or the lookup returns null.

Common situations: Custom gateway/decision behaviors selecting a transition by name that doesn't exist on the activity; process XML missing the expected sequence flow so the resolved transition is null; programmatic model building where a flow was never attached.

Related errors


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

Appendix: source

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

            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<>();
        if (isConcurrent()) {
            List<? extends ActivityExecution> concurrentExecutions = getParent().getExecutions();
            for (ActivityExecution concurrentExecution : concurrentExecutions) {

View on GitHub (pinned to d6d39ce1c6)