: / Knowledge Base / ERPNext Frappe Workflow Order Matters

ERPNext Frappe Workflow Order Matters


Created:5/7/2026


TLDR

The order of workflow transitions matters. The transition with the higher idx (later in the list) has higher priority and will always win when multiple transitions match.

Excalidraw diagram

Use Case

For our Purchase Order workflow, we had two requirements:

  • If a Purchase User submits a PO, the state should become Pending Approval
  • If a Purchase Manager submits a PO, the state should go directly to Submitted

On our first try, we added transitions in this order:

  1. Draft -> Submitted (Allowed: Purchase Manager)
  2. Draft -> Pending Approval (Allowed: Purchase User)

We then noticed a problem: when a user with both the Purchase User and Purchase Manager roles submitted a PO, the document transitioned to Pending Approval instead of Submitted. That was wrong - anyone with the Purchase Manager role should bypass the approval step entirely.

So we dug a little deeper to understand why.

The Cause

It's not really a bug - it's just the way Frappe works.

The code lives in frappe/model/workflow.py, inside apply_workflow. After collecting all transitions the current user is eligible for, it picks the one matching the clicked action like this:

# find the transition
transition = None
for t in transitions:
    if t.action == action:
        transition = t        # ← last match overwrites

There's no break in the loop. Every matching transition overwrites the previous one, so the last eligible transition in the list wins.

get_transitions builds that list by iterating workflow.transitions in idx order:

for transition in workflow.transitions:
    if transition.state == current_state and transition.allowed in roles:
        if not is_transition_condition_satisfied(transition, doc):
            continue
        transitions.append(transition.as_dict())

So whichever transition appears later in the list (higher idx) is the one that gets applied - regardless of role hierarchy.

The Fix

Reorder your transitions so that the more specific or higher-priority one comes last. In our case, we simply swapped the order:

  1. Draft -> Pending Approval (Allowed: Purchase User)
  2. Draft -> Submitted (Allowed: Purchase Manager)

Now when a Purchase Manager submits a PO, both transitions match - but since "Draft -> Submitted" is last in the list, it wins. The general rule: put your most privileged or specific transitions at the bottom.


Need a hand?We're here to help you solve it - fast, simple, and stress-free.
Hire Us