Skip to content

Commit 9c087cd

Browse files
committed
fix(parallel): error-sticky block run status to prevent branch success masking failure
1 parent 6b407ee commit 9c087cd

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ import {
2020
TriggerUtils,
2121
} from '@/lib/workflows/triggers/triggers'
2222
import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow'
23-
import { updateActiveBlockRefCount } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils'
23+
import {
24+
resolveBlockRunStatus,
25+
updateActiveBlockRefCount,
26+
} from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils'
2427
import { getBlock } from '@/blocks'
2528
import type { SerializableExecutionState } from '@/executor/execution/types'
2629
import type {
@@ -65,6 +68,8 @@ interface BlockEventHandlerConfig {
6568
workflowEdges: Array<{ id: string; target: string; sourceHandle?: string | null }>
6669
activeBlocksSet: Set<string>
6770
activeBlockRefCounts: Map<string, number>
71+
/** Tracks blocks that have errored in any parallel branch — prevents later success from masking errors. */
72+
blockRunErrors: Set<string>
6873
accumulatedBlockLogs: BlockLog[]
6974
accumulatedBlockStates: Map<string, BlockState>
7075
executedBlockIds: Set<string>
@@ -312,6 +317,7 @@ export function useWorkflowExecution() {
312317
workflowEdges,
313318
activeBlocksSet,
314319
activeBlockRefCounts,
320+
blockRunErrors,
315321
accumulatedBlockLogs,
316322
accumulatedBlockStates,
317323
executedBlockIds,
@@ -484,7 +490,12 @@ export function useWorkflowExecution() {
484490
const onBlockCompleted = (data: BlockCompletedData) => {
485491
if (isStaleExecution()) return
486492
updateActiveBlocks(data.blockId, false)
487-
if (workflowId) setBlockRunStatus(workflowId, data.blockId, 'success')
493+
if (workflowId)
494+
setBlockRunStatus(
495+
workflowId,
496+
data.blockId,
497+
resolveBlockRunStatus(blockRunErrors, data.blockId, 'success')
498+
)
488499

489500
executedBlockIds.add(data.blockId)
490501
accumulatedBlockStates.set(data.blockId, {
@@ -515,7 +526,12 @@ export function useWorkflowExecution() {
515526
const onBlockError = (data: BlockErrorData) => {
516527
if (isStaleExecution()) return
517528
updateActiveBlocks(data.blockId, false)
518-
if (workflowId) setBlockRunStatus(workflowId, data.blockId, 'error')
529+
if (workflowId)
530+
setBlockRunStatus(
531+
workflowId,
532+
data.blockId,
533+
resolveBlockRunStatus(blockRunErrors, data.blockId, 'error')
534+
)
519535

520536
executedBlockIds.add(data.blockId)
521537
accumulatedBlockStates.set(data.blockId, {
@@ -1280,6 +1296,7 @@ export function useWorkflowExecution() {
12801296

12811297
const activeBlocksSet = new Set<string>()
12821298
const activeBlockRefCounts = new Map<string, number>()
1299+
const blockRunErrors = new Set<string>()
12831300
const streamedContent = new Map<string, string>()
12841301
const accumulatedBlockLogs: BlockLog[] = []
12851302
const accumulatedBlockStates = new Map<string, BlockState>()
@@ -1293,6 +1310,7 @@ export function useWorkflowExecution() {
12931310
workflowEdges,
12941311
activeBlocksSet,
12951312
activeBlockRefCounts,
1313+
blockRunErrors,
12961314
accumulatedBlockLogs,
12971315
accumulatedBlockStates,
12981316
executedBlockIds,
@@ -1904,6 +1922,7 @@ export function useWorkflowExecution() {
19041922
const executedBlockIds = new Set<string>()
19051923
const activeBlocksSet = new Set<string>()
19061924
const activeBlockRefCounts = new Map<string, number>()
1925+
const blockRunErrors = new Set<string>()
19071926

19081927
try {
19091928
const blockHandlers = buildBlockEventHandlers({
@@ -1912,6 +1931,7 @@ export function useWorkflowExecution() {
19121931
workflowEdges,
19131932
activeBlocksSet,
19141933
activeBlockRefCounts,
1934+
blockRunErrors,
19151935
accumulatedBlockLogs,
19161936
accumulatedBlockStates,
19171937
executedBlockIds,
@@ -2108,6 +2128,7 @@ export function useWorkflowExecution() {
21082128
const workflowEdges = useWorkflowStore.getState().edges
21092129
const activeBlocksSet = new Set<string>()
21102130
const activeBlockRefCounts = new Map<string, number>()
2131+
const blockRunErrors = new Set<string>()
21112132
const accumulatedBlockLogs: BlockLog[] = []
21122133
const accumulatedBlockStates = new Map<string, BlockState>()
21132134
const executedBlockIds = new Set<string>()
@@ -2120,6 +2141,7 @@ export function useWorkflowExecution() {
21202141
workflowEdges,
21212142
activeBlocksSet,
21222143
activeBlockRefCounts,
2144+
blockRunErrors,
21232145
accumulatedBlockLogs,
21242146
accumulatedBlockStates,
21252147
executedBlockIds,

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ import { useTerminalConsoleStore } from '@/stores/terminal'
55
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
66
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
77

8+
/**
9+
* Returns the run status to persist for a block, using an error-sticky policy.
10+
* Once any parallel branch for a block has errored, the block status stays 'error'
11+
* even if a later branch completes successfully — preventing failures from being masked.
12+
*/
13+
export function resolveBlockRunStatus(
14+
erroredBlocks: Set<string>,
15+
blockId: string,
16+
status: 'success' | 'error'
17+
): 'success' | 'error' {
18+
if (status === 'error') {
19+
erroredBlocks.add(blockId)
20+
}
21+
return erroredBlocks.has(blockId) ? 'error' : 'success'
22+
}
23+
824
/**
925
* Updates the active blocks set and ref counts for a single block.
1026
* Ref counting ensures a block stays active until all parallel branches for it complete.
@@ -64,6 +80,7 @@ export async function executeWorkflowWithFullLogging(
6480

6581
const activeBlocksSet = new Set<string>()
6682
const activeBlockRefCounts = new Map<string, number>()
83+
const blockRunErrors = new Set<string>()
6784

6885
const payload: any = {
6986
input: options.workflowInput,
@@ -154,7 +171,11 @@ export async function executeWorkflowWithFullLogging(
154171
)
155172
setActiveBlocks(wfId, new Set(activeBlocksSet))
156173

157-
setBlockRunStatus(wfId, event.data.blockId, 'success')
174+
setBlockRunStatus(
175+
wfId,
176+
event.data.blockId,
177+
resolveBlockRunStatus(blockRunErrors, event.data.blockId, 'success')
178+
)
158179

159180
addConsole({
160181
input: event.data.input || {},
@@ -190,7 +211,11 @@ export async function executeWorkflowWithFullLogging(
190211
)
191212
setActiveBlocks(wfId, new Set(activeBlocksSet))
192213

193-
setBlockRunStatus(wfId, event.data.blockId, 'error')
214+
setBlockRunStatus(
215+
wfId,
216+
event.data.blockId,
217+
resolveBlockRunStatus(blockRunErrors, event.data.blockId, 'error')
218+
)
194219

195220
addConsole({
196221
input: event.data.input || {},

0 commit comments

Comments
 (0)