We're reclaiming inactive PDIs to keep them available for active builders. Learn what's changing, who's affected, and how to protect your work. Read More

PlanRecursionException in Bidirectional Stage-Based Flows: Least Invasive Solution?

ClaudioG4376288
Tera Contributor

Hi ServiceNow Community,

I am looking for advice on the least invasive and most upgrade-safe solution to address a PlanRecursionException, without increasing the platform recursion limit.

We have implemented a stage-based process on a custom Case table.

When a Case is created, the process is managed through multiple record-triggered flows operating on the same Case record.

The design works as follows:

  1. Each flow is associated with a specific stage.
  2. A flow is triggered when the stage field changes to the corresponding value.
  3. The flow performs the activities required for that stage.
  4. At the end, the flow updates the same Case record by setting the stage field to the value expected by the trigger of the next flow.

In a simplified forward path:

 

Case created
→ Stage changes to A
→ Flow A starts
→ Flow A performs its actions
→ Flow A sets Stage to B
→ Flow B starts
→ Flow B performs its actions
→ Flow B sets Stage to C

 

However, the process is bidirectional. A Case can both advance and move back to a previous stage.

For example, when an approval is rejected or not granted, the current flow may set the stage field back to a previous value:

 

Flow A → Stage B → Flow B → approval rejected
→ Stage is set back to A
→ Flow A is triggered again

 

Therefore, returning to an earlier stage is an expected business scenario, not necessarily an unintended technical infinite loop. Nevertheless, this backward transition re-enters a flow that has already been part of the current execution chain, which appears to be the reason why ServiceNow detects plan recursion.

The preceding flow is shown as Completed, and the Case record is updated correctly. However, the flow associated with the new stage is not created in the Flow Executions list.

The system log contains the following error:

 

Failed to run flow trigger for trigger runner with identifier:
1837797e3b10c310c866b31864e45ad4
of class:
com.glide.flow_trigger.engine.RecordTriggerRunner
 
com.snc.process_flow.exception.PlanRecursionException:
Plan recursion has been encountered

 

The stack trace shows that the error occurs after a RecordUpdateOperation.

The apparent sequence is:

 

The current flow updates the Stage field
→ the Case record is updated
→ the record trigger associated with the new stage is evaluated
→ ServiceNow attempts to start the corresponding flow
→ the Flow Designer recursion check blocks the execution
→ no new flow context is created
`

 

This is particularly relevant in the rejection path:

 

Stage A → Stage B → approval not granted → Stage A

 

From a business perspective, the Case must legitimately return to Stage A and repeat some or all of the processing associated with that stage. From the Flow Designer engine perspective, however, this seems to be considered recursion because the same flow plan is started again within the existing execution chain.

We would prefer not to:

  • increase the recursion limit;
  • redesign the entire process;
  • remove the ability to return to a previous stage;
  • lose the modularity provided by having one flow for each stage.

What would be the recommended and least invasive approach for this scenario?

 

Thank you.

1 REPLY 1

Vikram Reddy
Tera Guru

Hey @ClaudioG4376288,

 

// End of Flow A / Flow B, replace the direct
// "Update Record" step on Case with:

gs.eventQueueScheduled('case.stage.transition', current, current.stage.toString(), '', gs.now());

Point the downstream flow's trigger at the sysevent table instead of Case (add sysevent to sn_flow_designer.allowed_system_tables if it isn't selectable yet), filtered on that event name. The stack trace names com.glide.flow_trigger.engine.RecordTriggerRunner specifically, that's the piece walking the current plan's execution chain and blocking re-entry into a flow already in it. An event fired this way runs on its own transaction, so the next stage's flow starts a fresh execution chain instead of nesting inside the one Flow A is still part of. No recursion limit change, no redesign, each stage keeps its own flow.

 

Thank you,
Vikram Karety
Octigo Solutions INC