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
- Null-check the transition before calling take() and throw a descriptive error
- Verify the process definition actually contains the outgoing sequence flow being selected
- Fix transition-selection logic (match by flow id/name) to fall back to a default flow
- 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
- Null-check transitions resolved by name/id before take()
- Ensure process XML defines all referenced sequence flows
- Default to a fallback flow when dynamic selection fails
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
- activatedBefore is null
- activity tenant id is null
- activity tenant id is null
- after time is null
- after time is null
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)