From cbb98a08686168fe33d2f78b46d2e5734a4f63fb Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 14 Feb 2026 12:58:18 -0800 Subject: [PATCH 1/5] fix(executor): resolve block ID for parallel subflow active state --- .../hooks/use-workflow-execution.ts | 19 +++++++++++++- .../utils/workflow-execution-utils.ts | 25 ++++++++++++++++--- apps/sim/executor/execution/block-executor.ts | 4 +-- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index 1088f8c87f..fceade9a1b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -63,6 +63,7 @@ interface BlockEventHandlerConfig { executionIdRef: { current: string } workflowEdges: Array<{ id: string; target: string; sourceHandle?: string | null }> activeBlocksSet: Set + activeBlockRefCounts: Map accumulatedBlockLogs: BlockLog[] accumulatedBlockStates: Map executedBlockIds: Set @@ -309,6 +310,7 @@ export function useWorkflowExecution() { executionIdRef, workflowEdges, activeBlocksSet, + activeBlockRefCounts, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -328,9 +330,18 @@ export function useWorkflowExecution() { const updateActiveBlocks = (blockId: string, isActive: boolean) => { if (!workflowId) return if (isActive) { + const count = activeBlockRefCounts.get(blockId) ?? 0 + activeBlockRefCounts.set(blockId, count + 1) activeBlocksSet.add(blockId) } else { - activeBlocksSet.delete(blockId) + const count = activeBlockRefCounts.get(blockId) ?? 1 + const next = count - 1 + if (next <= 0) { + activeBlockRefCounts.delete(blockId) + activeBlocksSet.delete(blockId) + } else { + activeBlockRefCounts.set(blockId, next) + } } setActiveBlocks(workflowId, new Set(activeBlocksSet)) } @@ -1280,6 +1291,7 @@ export function useWorkflowExecution() { } const activeBlocksSet = new Set() + const activeBlockRefCounts = new Map() const streamedContent = new Map() const accumulatedBlockLogs: BlockLog[] = [] const accumulatedBlockStates = new Map() @@ -1292,6 +1304,7 @@ export function useWorkflowExecution() { executionIdRef, workflowEdges, activeBlocksSet, + activeBlockRefCounts, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -1902,6 +1915,7 @@ export function useWorkflowExecution() { const accumulatedBlockStates = new Map() const executedBlockIds = new Set() const activeBlocksSet = new Set() + const activeBlockRefCounts = new Map() try { const blockHandlers = buildBlockEventHandlers({ @@ -1909,6 +1923,7 @@ export function useWorkflowExecution() { executionIdRef, workflowEdges, activeBlocksSet, + activeBlockRefCounts, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -2104,6 +2119,7 @@ export function useWorkflowExecution() { const workflowEdges = useWorkflowStore.getState().edges const activeBlocksSet = new Set() + const activeBlockRefCounts = new Map() const accumulatedBlockLogs: BlockLog[] = [] const accumulatedBlockStates = new Map() const executedBlockIds = new Set() @@ -2115,6 +2131,7 @@ export function useWorkflowExecution() { executionIdRef, workflowEdges, activeBlocksSet, + activeBlockRefCounts, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts index c0e54ea437..bf5e2e531b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts @@ -39,6 +39,7 @@ export async function executeWorkflowWithFullLogging( const workflowEdges = useWorkflowStore.getState().edges const activeBlocksSet = new Set() + const activeBlockRefCounts = new Map() const payload: any = { input: options.workflowInput, @@ -103,6 +104,8 @@ export async function executeWorkflowWithFullLogging( switch (event.type) { case 'block:started': { + const startCount = activeBlockRefCounts.get(event.data.blockId) ?? 0 + activeBlockRefCounts.set(event.data.blockId, startCount + 1) activeBlocksSet.add(event.data.blockId) setActiveBlocks(wfId, new Set(activeBlocksSet)) @@ -115,8 +118,14 @@ export async function executeWorkflowWithFullLogging( break } - case 'block:completed': - activeBlocksSet.delete(event.data.blockId) + case 'block:completed': { + const completeCount = activeBlockRefCounts.get(event.data.blockId) ?? 1 + if (completeCount <= 1) { + activeBlockRefCounts.delete(event.data.blockId) + activeBlocksSet.delete(event.data.blockId) + } else { + activeBlockRefCounts.set(event.data.blockId, completeCount - 1) + } setActiveBlocks(wfId, new Set(activeBlocksSet)) setBlockRunStatus(wfId, event.data.blockId, 'success') @@ -144,9 +153,16 @@ export async function executeWorkflowWithFullLogging( options.onBlockComplete(event.data.blockId, event.data.output).catch(() => {}) } break + } - case 'block:error': - activeBlocksSet.delete(event.data.blockId) + case 'block:error': { + const errorCount = activeBlockRefCounts.get(event.data.blockId) ?? 1 + if (errorCount <= 1) { + activeBlockRefCounts.delete(event.data.blockId) + activeBlocksSet.delete(event.data.blockId) + } else { + activeBlockRefCounts.set(event.data.blockId, errorCount - 1) + } setActiveBlocks(wfId, new Set(activeBlocksSet)) setBlockRunStatus(wfId, event.data.blockId, 'error') @@ -171,6 +187,7 @@ export async function executeWorkflowWithFullLogging( iterationContainerId: event.data.iterationContainerId, }) break + } case 'execution:completed': executionResult = { diff --git a/apps/sim/executor/execution/block-executor.ts b/apps/sim/executor/execution/block-executor.ts index 58143e5832..56b7c6a915 100644 --- a/apps/sim/executor/execution/block-executor.ts +++ b/apps/sim/executor/execution/block-executor.ts @@ -428,7 +428,7 @@ export class BlockExecutor { block: SerializedBlock, executionOrder: number ): void { - const blockId = node.id + const blockId = node.metadata?.originalBlockId ?? node.id const blockName = block.metadata?.name ?? blockId const blockType = block.metadata?.id ?? DEFAULTS.BLOCK_TYPE @@ -456,7 +456,7 @@ export class BlockExecutor { executionOrder: number, endedAt: string ): void { - const blockId = node.id + const blockId = node.metadata?.originalBlockId ?? node.id const blockName = block.metadata?.name ?? blockId const blockType = block.metadata?.id ?? DEFAULTS.BLOCK_TYPE From 04fbe1d1859bd75e41da4e2e3c8928c51523d17e Mon Sep 17 00:00:00 2001 From: waleed Date: Sun, 22 Feb 2026 14:33:13 -0800 Subject: [PATCH 2/5] fix timing for parallel block --- .../w/[workflowId]/components/terminal/utils.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/utils.ts index 0c285a7b96..f1bb7b3dc8 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/utils.ts @@ -261,6 +261,9 @@ function buildEntryTree(entries: ConsoleEntry[]): EntryNode[] { ...allBlocks.map((b) => new Date(b.endedAt || b.timestamp).getTime()) ) const totalDuration = allBlocks.reduce((sum, b) => sum + (b.durationMs || 0), 0) + // Parallel branches run concurrently — use wall-clock time. Loop iterations run serially — use sum. + const subflowDuration = + iterationType === 'parallel' ? subflowEndMs - subflowStartMs : totalDuration // Create synthetic subflow parent entry // Use the minimum executionOrder from all child blocks for proper ordering @@ -276,7 +279,7 @@ function buildEntryTree(entries: ConsoleEntry[]): EntryNode[] { startedAt: new Date(subflowStartMs).toISOString(), executionOrder: subflowExecutionOrder, endedAt: new Date(subflowEndMs).toISOString(), - durationMs: totalDuration, + durationMs: subflowDuration, success: !allBlocks.some((b) => b.error), } @@ -291,6 +294,9 @@ function buildEntryTree(entries: ConsoleEntry[]): EntryNode[] { ...iterBlocks.map((b) => new Date(b.endedAt || b.timestamp).getTime()) ) const iterDuration = iterBlocks.reduce((sum, b) => sum + (b.durationMs || 0), 0) + // Parallel branches run concurrently — use wall-clock time. Loop iterations run serially — use sum. + const iterDisplayDuration = + iterationType === 'parallel' ? iterEndMs - iterStartMs : iterDuration // Use the minimum executionOrder from blocks in this iteration const iterExecutionOrder = Math.min(...iterBlocks.map((b) => b.executionOrder)) @@ -305,7 +311,7 @@ function buildEntryTree(entries: ConsoleEntry[]): EntryNode[] { startedAt: new Date(iterStartMs).toISOString(), executionOrder: iterExecutionOrder, endedAt: new Date(iterEndMs).toISOString(), - durationMs: iterDuration, + durationMs: iterDisplayDuration, success: !iterBlocks.some((b) => b.error), iterationCurrent: iterGroup.iterationCurrent, iterationTotal: iterGroup.iterationTotal, From 6b407eeb608dc3a34fb47a6435e07144cdd3dffb Mon Sep 17 00:00:00 2001 From: waleed Date: Sun, 22 Feb 2026 14:39:50 -0800 Subject: [PATCH 3/5] refactor(parallel): extract shared updateActiveBlockRefCount helper --- .../hooks/use-workflow-execution.ts | 16 +---- .../utils/workflow-execution-utils.ts | 59 +++++++++++++------ 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index fceade9a1b..10186d6876 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -20,6 +20,7 @@ import { TriggerUtils, } from '@/lib/workflows/triggers/triggers' import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow' +import { updateActiveBlockRefCount } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils' import { getBlock } from '@/blocks' import type { SerializableExecutionState } from '@/executor/execution/types' import type { @@ -329,20 +330,7 @@ export function useWorkflowExecution() { const updateActiveBlocks = (blockId: string, isActive: boolean) => { if (!workflowId) return - if (isActive) { - const count = activeBlockRefCounts.get(blockId) ?? 0 - activeBlockRefCounts.set(blockId, count + 1) - activeBlocksSet.add(blockId) - } else { - const count = activeBlockRefCounts.get(blockId) ?? 1 - const next = count - 1 - if (next <= 0) { - activeBlockRefCounts.delete(blockId) - activeBlocksSet.delete(blockId) - } else { - activeBlockRefCounts.set(blockId, next) - } - } + updateActiveBlockRefCount(activeBlockRefCounts, activeBlocksSet, blockId, isActive) setActiveBlocks(workflowId, new Set(activeBlocksSet)) } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts index bf5e2e531b..ff1baf222a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts @@ -5,6 +5,30 @@ import { useTerminalConsoleStore } from '@/stores/terminal' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' +/** + * Updates the active blocks set and ref counts for a single block. + * Ref counting ensures a block stays active until all parallel branches for it complete. + */ +export function updateActiveBlockRefCount( + refCounts: Map, + activeSet: Set, + blockId: string, + isActive: boolean +): void { + if (isActive) { + refCounts.set(blockId, (refCounts.get(blockId) ?? 0) + 1) + activeSet.add(blockId) + } else { + const next = (refCounts.get(blockId) ?? 1) - 1 + if (next <= 0) { + refCounts.delete(blockId) + activeSet.delete(blockId) + } else { + refCounts.set(blockId, next) + } + } +} + export interface WorkflowExecutionOptions { workflowInput?: any onStream?: (se: StreamingExecution) => Promise @@ -104,9 +128,12 @@ export async function executeWorkflowWithFullLogging( switch (event.type) { case 'block:started': { - const startCount = activeBlockRefCounts.get(event.data.blockId) ?? 0 - activeBlockRefCounts.set(event.data.blockId, startCount + 1) - activeBlocksSet.add(event.data.blockId) + updateActiveBlockRefCount( + activeBlockRefCounts, + activeBlocksSet, + event.data.blockId, + true + ) setActiveBlocks(wfId, new Set(activeBlocksSet)) const incomingEdges = workflowEdges.filter( @@ -119,13 +146,12 @@ export async function executeWorkflowWithFullLogging( } case 'block:completed': { - const completeCount = activeBlockRefCounts.get(event.data.blockId) ?? 1 - if (completeCount <= 1) { - activeBlockRefCounts.delete(event.data.blockId) - activeBlocksSet.delete(event.data.blockId) - } else { - activeBlockRefCounts.set(event.data.blockId, completeCount - 1) - } + updateActiveBlockRefCount( + activeBlockRefCounts, + activeBlocksSet, + event.data.blockId, + false + ) setActiveBlocks(wfId, new Set(activeBlocksSet)) setBlockRunStatus(wfId, event.data.blockId, 'success') @@ -156,13 +182,12 @@ export async function executeWorkflowWithFullLogging( } case 'block:error': { - const errorCount = activeBlockRefCounts.get(event.data.blockId) ?? 1 - if (errorCount <= 1) { - activeBlockRefCounts.delete(event.data.blockId) - activeBlocksSet.delete(event.data.blockId) - } else { - activeBlockRefCounts.set(event.data.blockId, errorCount - 1) - } + updateActiveBlockRefCount( + activeBlockRefCounts, + activeBlocksSet, + event.data.blockId, + false + ) setActiveBlocks(wfId, new Set(activeBlocksSet)) setBlockRunStatus(wfId, event.data.blockId, 'error') From 9c087cd466ac67bcc6713c613d80c0878b2a33bb Mon Sep 17 00:00:00 2001 From: waleed Date: Sun, 22 Feb 2026 15:01:00 -0800 Subject: [PATCH 4/5] fix(parallel): error-sticky block run status to prevent branch success masking failure --- .../hooks/use-workflow-execution.ts | 28 ++++++++++++++++-- .../utils/workflow-execution-utils.ts | 29 +++++++++++++++++-- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index 10186d6876..9754879ac9 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -20,7 +20,10 @@ import { TriggerUtils, } from '@/lib/workflows/triggers/triggers' import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow' -import { updateActiveBlockRefCount } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils' +import { + resolveBlockRunStatus, + updateActiveBlockRefCount, +} from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils' import { getBlock } from '@/blocks' import type { SerializableExecutionState } from '@/executor/execution/types' import type { @@ -65,6 +68,8 @@ interface BlockEventHandlerConfig { workflowEdges: Array<{ id: string; target: string; sourceHandle?: string | null }> activeBlocksSet: Set activeBlockRefCounts: Map + /** Tracks blocks that have errored in any parallel branch — prevents later success from masking errors. */ + blockRunErrors: Set accumulatedBlockLogs: BlockLog[] accumulatedBlockStates: Map executedBlockIds: Set @@ -312,6 +317,7 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, + blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -484,7 +490,12 @@ export function useWorkflowExecution() { const onBlockCompleted = (data: BlockCompletedData) => { if (isStaleExecution()) return updateActiveBlocks(data.blockId, false) - if (workflowId) setBlockRunStatus(workflowId, data.blockId, 'success') + if (workflowId) + setBlockRunStatus( + workflowId, + data.blockId, + resolveBlockRunStatus(blockRunErrors, data.blockId, 'success') + ) executedBlockIds.add(data.blockId) accumulatedBlockStates.set(data.blockId, { @@ -515,7 +526,12 @@ export function useWorkflowExecution() { const onBlockError = (data: BlockErrorData) => { if (isStaleExecution()) return updateActiveBlocks(data.blockId, false) - if (workflowId) setBlockRunStatus(workflowId, data.blockId, 'error') + if (workflowId) + setBlockRunStatus( + workflowId, + data.blockId, + resolveBlockRunStatus(blockRunErrors, data.blockId, 'error') + ) executedBlockIds.add(data.blockId) accumulatedBlockStates.set(data.blockId, { @@ -1280,6 +1296,7 @@ export function useWorkflowExecution() { const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() + const blockRunErrors = new Set() const streamedContent = new Map() const accumulatedBlockLogs: BlockLog[] = [] const accumulatedBlockStates = new Map() @@ -1293,6 +1310,7 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, + blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -1904,6 +1922,7 @@ export function useWorkflowExecution() { const executedBlockIds = new Set() const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() + const blockRunErrors = new Set() try { const blockHandlers = buildBlockEventHandlers({ @@ -1912,6 +1931,7 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, + blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -2108,6 +2128,7 @@ export function useWorkflowExecution() { const workflowEdges = useWorkflowStore.getState().edges const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() + const blockRunErrors = new Set() const accumulatedBlockLogs: BlockLog[] = [] const accumulatedBlockStates = new Map() const executedBlockIds = new Set() @@ -2120,6 +2141,7 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, + blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts index ff1baf222a..988726070d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts @@ -5,6 +5,22 @@ import { useTerminalConsoleStore } from '@/stores/terminal' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' +/** + * Returns the run status to persist for a block, using an error-sticky policy. + * Once any parallel branch for a block has errored, the block status stays 'error' + * even if a later branch completes successfully — preventing failures from being masked. + */ +export function resolveBlockRunStatus( + erroredBlocks: Set, + blockId: string, + status: 'success' | 'error' +): 'success' | 'error' { + if (status === 'error') { + erroredBlocks.add(blockId) + } + return erroredBlocks.has(blockId) ? 'error' : 'success' +} + /** * Updates the active blocks set and ref counts for a single block. * Ref counting ensures a block stays active until all parallel branches for it complete. @@ -64,6 +80,7 @@ export async function executeWorkflowWithFullLogging( const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() + const blockRunErrors = new Set() const payload: any = { input: options.workflowInput, @@ -154,7 +171,11 @@ export async function executeWorkflowWithFullLogging( ) setActiveBlocks(wfId, new Set(activeBlocksSet)) - setBlockRunStatus(wfId, event.data.blockId, 'success') + setBlockRunStatus( + wfId, + event.data.blockId, + resolveBlockRunStatus(blockRunErrors, event.data.blockId, 'success') + ) addConsole({ input: event.data.input || {}, @@ -190,7 +211,11 @@ export async function executeWorkflowWithFullLogging( ) setActiveBlocks(wfId, new Set(activeBlocksSet)) - setBlockRunStatus(wfId, event.data.blockId, 'error') + setBlockRunStatus( + wfId, + event.data.blockId, + resolveBlockRunStatus(blockRunErrors, event.data.blockId, 'error') + ) addConsole({ input: event.data.input || {}, From b5ca145bd8186a5db844da3baa5a45500dda387d Mon Sep 17 00:00:00 2001 From: waleed Date: Sun, 22 Feb 2026 15:03:07 -0800 Subject: [PATCH 5/5] Revert "fix(parallel): error-sticky block run status to prevent branch success masking failure" This reverts commit 9c087cd466ac67bcc6713c613d80c0878b2a33bb. --- .../hooks/use-workflow-execution.ts | 28 ++---------------- .../utils/workflow-execution-utils.ts | 29 ++----------------- 2 files changed, 5 insertions(+), 52 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index 9754879ac9..10186d6876 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -20,10 +20,7 @@ import { TriggerUtils, } from '@/lib/workflows/triggers/triggers' import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow' -import { - resolveBlockRunStatus, - updateActiveBlockRefCount, -} from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils' +import { updateActiveBlockRefCount } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils' import { getBlock } from '@/blocks' import type { SerializableExecutionState } from '@/executor/execution/types' import type { @@ -68,8 +65,6 @@ interface BlockEventHandlerConfig { workflowEdges: Array<{ id: string; target: string; sourceHandle?: string | null }> activeBlocksSet: Set activeBlockRefCounts: Map - /** Tracks blocks that have errored in any parallel branch — prevents later success from masking errors. */ - blockRunErrors: Set accumulatedBlockLogs: BlockLog[] accumulatedBlockStates: Map executedBlockIds: Set @@ -317,7 +312,6 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, - blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -490,12 +484,7 @@ export function useWorkflowExecution() { const onBlockCompleted = (data: BlockCompletedData) => { if (isStaleExecution()) return updateActiveBlocks(data.blockId, false) - if (workflowId) - setBlockRunStatus( - workflowId, - data.blockId, - resolveBlockRunStatus(blockRunErrors, data.blockId, 'success') - ) + if (workflowId) setBlockRunStatus(workflowId, data.blockId, 'success') executedBlockIds.add(data.blockId) accumulatedBlockStates.set(data.blockId, { @@ -526,12 +515,7 @@ export function useWorkflowExecution() { const onBlockError = (data: BlockErrorData) => { if (isStaleExecution()) return updateActiveBlocks(data.blockId, false) - if (workflowId) - setBlockRunStatus( - workflowId, - data.blockId, - resolveBlockRunStatus(blockRunErrors, data.blockId, 'error') - ) + if (workflowId) setBlockRunStatus(workflowId, data.blockId, 'error') executedBlockIds.add(data.blockId) accumulatedBlockStates.set(data.blockId, { @@ -1296,7 +1280,6 @@ export function useWorkflowExecution() { const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() - const blockRunErrors = new Set() const streamedContent = new Map() const accumulatedBlockLogs: BlockLog[] = [] const accumulatedBlockStates = new Map() @@ -1310,7 +1293,6 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, - blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -1922,7 +1904,6 @@ export function useWorkflowExecution() { const executedBlockIds = new Set() const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() - const blockRunErrors = new Set() try { const blockHandlers = buildBlockEventHandlers({ @@ -1931,7 +1912,6 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, - blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, @@ -2128,7 +2108,6 @@ export function useWorkflowExecution() { const workflowEdges = useWorkflowStore.getState().edges const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() - const blockRunErrors = new Set() const accumulatedBlockLogs: BlockLog[] = [] const accumulatedBlockStates = new Map() const executedBlockIds = new Set() @@ -2141,7 +2120,6 @@ export function useWorkflowExecution() { workflowEdges, activeBlocksSet, activeBlockRefCounts, - blockRunErrors, accumulatedBlockLogs, accumulatedBlockStates, executedBlockIds, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts index 988726070d..ff1baf222a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts @@ -5,22 +5,6 @@ import { useTerminalConsoleStore } from '@/stores/terminal' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' -/** - * Returns the run status to persist for a block, using an error-sticky policy. - * Once any parallel branch for a block has errored, the block status stays 'error' - * even if a later branch completes successfully — preventing failures from being masked. - */ -export function resolveBlockRunStatus( - erroredBlocks: Set, - blockId: string, - status: 'success' | 'error' -): 'success' | 'error' { - if (status === 'error') { - erroredBlocks.add(blockId) - } - return erroredBlocks.has(blockId) ? 'error' : 'success' -} - /** * Updates the active blocks set and ref counts for a single block. * Ref counting ensures a block stays active until all parallel branches for it complete. @@ -80,7 +64,6 @@ export async function executeWorkflowWithFullLogging( const activeBlocksSet = new Set() const activeBlockRefCounts = new Map() - const blockRunErrors = new Set() const payload: any = { input: options.workflowInput, @@ -171,11 +154,7 @@ export async function executeWorkflowWithFullLogging( ) setActiveBlocks(wfId, new Set(activeBlocksSet)) - setBlockRunStatus( - wfId, - event.data.blockId, - resolveBlockRunStatus(blockRunErrors, event.data.blockId, 'success') - ) + setBlockRunStatus(wfId, event.data.blockId, 'success') addConsole({ input: event.data.input || {}, @@ -211,11 +190,7 @@ export async function executeWorkflowWithFullLogging( ) setActiveBlocks(wfId, new Set(activeBlocksSet)) - setBlockRunStatus( - wfId, - event.data.blockId, - resolveBlockRunStatus(blockRunErrors, event.data.blockId, 'error') - ) + setBlockRunStatus(wfId, event.data.blockId, 'error') addConsole({ input: event.data.input || {},