Skip to content

Commit 67c2efd

Browse files
committed
fix(logs): surface handled errors as info in logs
1 parent 8a24b56 commit 67c2efd

File tree

11 files changed

+571
-15
lines changed

11 files changed

+571
-15
lines changed

apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function parseTime(value?: string | number | null): number {
6767
}
6868

6969
/**
70-
* Checks if a span or any of its descendants has an error
70+
* Checks if a span or any of its descendants has an error (any error).
7171
*/
7272
function hasErrorInTree(span: TraceSpan): boolean {
7373
if (span.status === 'error') return true
@@ -80,6 +80,22 @@ function hasErrorInTree(span: TraceSpan): boolean {
8080
return false
8181
}
8282

83+
/**
84+
* Checks if a span or any of its descendants has an unhandled error.
85+
* Errors handled by error handler paths (errorHandled: true) are skipped.
86+
* Used only for the root workflow span to match the actual workflow status.
87+
*/
88+
function hasUnhandledErrorInTree(span: TraceSpan): boolean {
89+
if (span.status === 'error' && !span.errorHandled) return true
90+
if (span.children && span.children.length > 0) {
91+
return span.children.some((child) => hasUnhandledErrorInTree(child))
92+
}
93+
if (span.toolCalls && span.toolCalls.length > 0) {
94+
return span.toolCalls.some((tc) => tc.error)
95+
}
96+
return false
97+
}
98+
8399
/**
84100
* Normalizes and sorts trace spans recursively.
85101
* Deduplicates children and sorts by start time.
@@ -478,14 +494,13 @@ const TraceSpanNode = memo(function TraceSpanNode({
478494
const duration = span.duration || spanEndTime - spanStartTime
479495

480496
const isDirectError = span.status === 'error'
481-
const hasNestedError = hasErrorInTree(span)
497+
const isRootWorkflow = depth === 0
498+
const isRootWorkflowSpan = isRootWorkflow && span.type?.toLowerCase() === 'workflow'
499+
const hasNestedError = isRootWorkflowSpan ? hasUnhandledErrorInTree(span) : hasErrorInTree(span)
482500
const showErrorStyle = isDirectError || hasNestedError
483501

484502
const { icon: BlockIcon, bgColor } = getBlockIconAndColor(span.type, span.name)
485503

486-
// Root workflow execution is always expanded and has no toggle
487-
const isRootWorkflow = depth === 0
488-
489504
// Build all children including tool calls
490505
const allChildren = useMemo(() => {
491506
const children: TraceSpan[] = []

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-edge/workflow-edge.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ const WorkflowEdgeComponent = ({
9595
color = 'var(--brand-tertiary-2)'
9696
} else if (edgeRunStatus === 'success') {
9797
// Use green for preview mode, default for canvas execution
98-
// This also applies to error edges that were taken (error path executed)
9998
color = previewExecutionStatus ? 'var(--brand-tertiary-2)' : 'var(--border-success)'
10099
} else if (edgeRunStatus === 'error') {
101100
color = 'var(--text-error)'

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ interface DebugValidationResult {
5555
interface BlockEventHandlerConfig {
5656
workflowId?: string
5757
executionId?: string
58-
workflowEdges: Array<{ id: string; target: string }>
58+
workflowEdges: Array<{ id: string; target: string; sourceHandle?: string | null }>
5959
activeBlocksSet: Set<string>
6060
accumulatedBlockLogs: BlockLog[]
6161
accumulatedBlockStates: Map<string, BlockState>
@@ -322,7 +322,8 @@ export function useWorkflowExecution() {
322322
if (!workflowId) return
323323
const incomingEdges = workflowEdges.filter((edge) => edge.target === blockId)
324324
incomingEdges.forEach((edge) => {
325-
setEdgeRunStatus(workflowId, edge.id, 'success')
325+
const status = edge.sourceHandle === 'error' ? 'error' : 'success'
326+
setEdgeRunStatus(workflowId, edge.id, status)
326327
})
327328
}
328329

apps/sim/executor/execution/block-executor.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ export class BlockExecutor {
288288

289289
const hasErrorPort = this.hasErrorPortEdge(node)
290290
if (hasErrorPort) {
291+
if (blockLog) {
292+
blockLog.errorHandled = true
293+
}
291294
logger.info('Block has error port - returning error output instead of throwing', {
292295
blockId: node.id,
293296
error: errorMessage,

apps/sim/executor/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ export interface BlockLog {
112112
output?: any
113113
input?: any
114114
error?: string
115+
/** Whether this error was handled by an error handler path (error port) */
116+
errorHandled?: boolean
115117
loopId?: string
116118
parallelId?: string
117119
iterationIndex?: number

apps/sim/lib/logs/execution/logger.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,12 @@ export class ExecutionLogger implements IExecutionLoggerService {
219219
| { traceSpans?: TraceSpan[] }
220220
| undefined
221221

222-
// Determine if workflow failed by checking trace spans for errors
222+
// Determine if workflow failed by checking trace spans for unhandled errors
223+
// Errors handled by error handler paths (errorHandled: true) don't count as workflow failures
223224
// Use the override if provided (for cost-only fallback scenarios)
224225
const hasErrors = traceSpans?.some((span: any) => {
225226
const checkSpanForErrors = (s: any): boolean => {
226-
if (s.status === 'error') return true
227+
if (s.status === 'error' && !s.errorHandled) return true
227228
if (s.children && Array.isArray(s.children)) {
228229
return s.children.some(checkSpanForErrors)
229230
}

apps/sim/lib/logs/execution/logging-session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ export class LoggingSession {
301301

302302
const hasErrors = traceSpans.some((span: any) => {
303303
const checkForErrors = (s: any): boolean => {
304-
if (s.status === 'error') return true
304+
if (s.status === 'error' && !s.errorHandled) return true
305305
if (s.children && Array.isArray(s.children)) {
306306
return s.children.some(checkForErrors)
307307
}

0 commit comments

Comments
 (0)