Skip to content

BPMN Gateway Mismatch Antipatterns

A gateway is a diamond in a BPMN model that splits the flow into paths or joins paths back together. A mismatch means the join type does not fit the split before it.

Deadlock. A parallel (AND) join waits until every incoming path has arrived. Suppose the split before it started only some of those paths. The join then waits forever, and the process cannot complete.

Lack of synchronization. Sound BPMN models complete properly. That means no end event is reached more than once in a run. A model that breaks this rule has a lack of synchronization.

Typical fix. An inclusive (OR) split may start a varying number of paths. Join those paths with an inclusive (OR) join. This join waits only for the paths that were actually activated. A parallel join in that place causes the deadlock.

Finding these errors. You do not have to spot them by eye. BPMN Analyzer is a model checker. It explores the possible states of a model. It reports deadlocks, livelocks, starvation, dead activities, and lack of synchronization. It also suggests quick fixes for the most common control-flow errors, including those that lead to deadlock and lack of synchronization.

For the wider ideas, see the articles Soundness of Process Models, Deadlock in Process Models, and Lack of Synchronization.

A support process receives a ticket. An inclusive split starts “Notify customer” and “Update billing”, each only when it applies. Often only one applies. A parallel join then waits for both, so the ticket never closes. The fix is to replace the parallel join with an inclusive join. It waits only for the tasks that actually started.

The facts here cover only the inclusive-split case and the tool support. Automated checks catch common control-flow errors, but this article does not claim they catch every mismatch.

Antipattern: an inclusive split joined by a parallel gateway can deadlock. Replace the join with an inclusive gateway.

Diagram source
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="http://example.org/bpmn">
<process id="ticket" isExecutable="false">
<startEvent id="start" name="Ticket received">
<outgoing>f1</outgoing>
</startEvent>
<inclusiveGateway id="split" name="Which apply?">
<incoming>f1</incoming>
<outgoing>f2</outgoing>
<outgoing>f3</outgoing>
</inclusiveGateway>
<task id="notify" name="Notify customer">
<incoming>f2</incoming>
<outgoing>f4</outgoing>
</task>
<task id="billing" name="Update billing">
<incoming>f3</incoming>
<outgoing>f5</outgoing>
</task>
<parallelGateway id="join" name="Wait for all">
<incoming>f4</incoming>
<incoming>f5</incoming>
<outgoing>f6</outgoing>
</parallelGateway>
<endEvent id="end" name="Ticket closed">
<incoming>f6</incoming>
</endEvent>
<sequenceFlow id="f1" sourceRef="start" targetRef="split" />
<sequenceFlow id="f2" sourceRef="split" targetRef="notify" />
<sequenceFlow id="f3" sourceRef="split" targetRef="billing" />
<sequenceFlow id="f4" sourceRef="notify" targetRef="join" />
<sequenceFlow id="f5" sourceRef="billing" targetRef="join" />
<sequenceFlow id="f6" sourceRef="join" targetRef="end" />
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_ticket">
<bpmndi:BPMNPlane id="BPMNPlane_ticket" bpmnElement="ticket">
<bpmndi:BPMNShape id="BPMNShape_start" bpmnElement="start">
<dc:Bounds x="80" y="102" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="68" y="143" width="60" height="28" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_split" bpmnElement="split" isMarkerVisible="true">
<dc:Bounds x="216" y="95" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="197" y="76" width="89" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_notify" bpmnElement="notify">
<dc:Bounds x="366" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_billing" bpmnElement="billing">
<dc:Bounds x="366" y="240" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_join" bpmnElement="join" isMarkerVisible="true">
<dc:Bounds x="566" y="95" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="548" y="76" width="86" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_end" bpmnElement="end">
<dc:Bounds x="716" y="102" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="710" y="143" width="48" height="28" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_f1" bpmnElement="f1">
<di:waypoint x="116" y="120" />
<di:waypoint x="216" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_f2" bpmnElement="f2">
<di:waypoint x="266" y="120" />
<di:waypoint x="366" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_f4" bpmnElement="f4">
<di:waypoint x="466" y="120" />
<di:waypoint x="566" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_f6" bpmnElement="f6">
<di:waypoint x="616" y="120" />
<di:waypoint x="716" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_f3" bpmnElement="f3">
<di:waypoint x="241" y="145" />
<di:waypoint x="241" y="280" />
<di:waypoint x="366" y="280" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_f5" bpmnElement="f5">
<di:waypoint x="466" y="280" />
<di:waypoint x="591" y="280" />
<di:waypoint x="591" y="145" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
  • Every inclusive (OR) split is closed by an inclusive join, not by a parallel join.
  • The model is checked for deadlocks and lack of synchronization, for example with a BPMN model checker.
  • Each process run reaches any end event at most once (proper completion).