From 6c1db2e7fb31f0013b290be8a8e9b4bd4b61fafd Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Wed, 25 Mar 2026 18:35:58 +0100 Subject: [PATCH] Do not run loop when iterator is skipped (#18964) When an If/Else branch skips an Iterator step (because the branch wasn't taken), the executor incorrectly entered the iterator's loop body. This happened because getNextStepIdsToExecute checked !hasProcessedAllItems on an undefined result, which evaluated to true, causing it to return initialLoopStepIds instead of the post-loop nextStepIds. Fix: Add a !executedStepOutput.shouldSkipStepExecution guard to the iterator condition in getNextStepIdsToExecute, consistent with the existing shouldFailSafely guard. --- ...orkflow-executor.workspace-service.spec.ts | 24 +++++++++++++++++++ .../workflow-executor.workspace-service.ts | 3 ++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/__tests__/workflow-executor.workspace-service.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/__tests__/workflow-executor.workspace-service.spec.ts index 9137da2d24..11f92fa2b6 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/__tests__/workflow-executor.workspace-service.spec.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/__tests__/workflow-executor.workspace-service.spec.ts @@ -529,6 +529,30 @@ describe('WorkflowExecutorWorkspaceService', () => { }); }); + it('should return nextStepIds for a skipped iterator instead of entering the loop', async () => { + const step = { + id: 'iterator-1', + type: WorkflowActionType.ITERATOR, + nextStepIds: ['after-loop'], + settings: { + input: { + initialLoopStepIds: ['loop-step-1'], + }, + }, + } as WorkflowAction; + + const result = await service.getNextStepIdsToExecute({ + executedStep: step, + executedStepOutput: { + shouldSkipStepExecution: true, + }, + }); + + expect(result).toEqual({ + nextStepIdsToExecute: ['after-loop'], + }); + }); + it('should return nextStepIdsToFailSafely for all branches when if-else is fail-safe', async () => { const step = { id: 'if-else-1', diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts index 7f0bda4cbe..212fb1715f 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts @@ -253,7 +253,8 @@ export class WorkflowExecutorWorkspaceService { if ( !iteratorStepResult?.hasProcessedAllItems && - !executedStepOutput.shouldFailSafely + !executedStepOutput.shouldFailSafely && + !executedStepOutput.shouldSkipStepExecution ) { const nextStepIdsToExecute = isString( executedStep.settings.input.initialLoopStepIds,