Skip to content

Commit 594bcac

Browse files
committed
type more code
1 parent d3f2031 commit 594bcac

File tree

6 files changed

+53
-28
lines changed

6 files changed

+53
-28
lines changed

apps/sim/app/api/workflows/[id]/execute/route.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { normalizeName } from '@/executor/constants'
3030
import { ExecutionSnapshot } from '@/executor/execution/snapshot'
3131
import type { ExecutionMetadata, IterationContext } from '@/executor/execution/types'
3232
import type { NormalizedBlockOutput, StreamingExecution } from '@/executor/types'
33+
import { hasExecutionResult } from '@/executor/utils/errors'
3334
import { Serializer } from '@/serializer'
3435
import { CORE_TRIGGER_TYPES, type CoreTriggerType } from '@/stores/logs/filters/types'
3536

@@ -467,17 +468,17 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
467468
}
468469

469470
return NextResponse.json(filteredResult)
470-
} catch (error: any) {
471-
const errorMessage = error.message || 'Unknown error'
471+
} catch (error: unknown) {
472+
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
472473
logger.error(`[${requestId}] Non-SSE execution failed: ${errorMessage}`)
473474

474-
const executionResult = error.executionResult
475+
const executionResult = hasExecutionResult(error) ? error.executionResult : undefined
475476

476477
return NextResponse.json(
477478
{
478479
success: false,
479480
output: executionResult?.output,
480-
error: executionResult?.error || error.message || 'Execution failed',
481+
error: executionResult?.error || errorMessage || 'Execution failed',
481482
metadata: executionResult?.metadata
482483
? {
483484
duration: executionResult.metadata.duration,
@@ -788,11 +789,11 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
788789

789790
// Cleanup base64 cache for this execution
790791
await cleanupExecutionBase64Cache(executionId)
791-
} catch (error: any) {
792-
const errorMessage = error.message || 'Unknown error'
792+
} catch (error: unknown) {
793+
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
793794
logger.error(`[${requestId}] SSE execution failed: ${errorMessage}`)
794795

795-
const executionResult = error.executionResult
796+
const executionResult = hasExecutionResult(error) ? error.executionResult : undefined
796797

797798
sendEvent({
798799
type: 'execution:error',

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

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
} from '@/lib/workflows/triggers/triggers'
1717
import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow'
1818
import type { BlockLog, ExecutionResult, StreamingExecution } from '@/executor/types'
19+
import { hasExecutionResult } from '@/executor/utils/errors'
1920
import { coerceValue } from '@/executor/utils/start-block'
2021
import { subscriptionKeys } from '@/hooks/queries/subscription'
2122
import { useExecutionStream } from '@/hooks/use-execution-stream'
@@ -76,17 +77,6 @@ function normalizeErrorMessage(error: unknown): string {
7677
return WORKFLOW_EXECUTION_FAILURE_MESSAGE
7778
}
7879

79-
function isExecutionResult(value: unknown): value is ExecutionResult {
80-
if (!isRecord(value)) return false
81-
return typeof value.success === 'boolean' && isRecord(value.output)
82-
}
83-
84-
function extractExecutionResult(error: unknown): ExecutionResult | null {
85-
if (!isRecord(error)) return null
86-
const candidate = error.executionResult
87-
return isExecutionResult(candidate) ? candidate : null
88-
}
89-
9080
export function useWorkflowExecution() {
9181
const queryClient = useQueryClient()
9282
const currentWorkflow = useCurrentWorkflow()
@@ -1138,11 +1128,11 @@ export function useWorkflowExecution() {
11381128

11391129
const handleExecutionError = (error: unknown, options?: { executionId?: string }) => {
11401130
const normalizedMessage = normalizeErrorMessage(error)
1141-
const executionResultFromError = extractExecutionResult(error)
11421131

11431132
let errorResult: ExecutionResult
11441133

1145-
if (executionResultFromError) {
1134+
if (hasExecutionResult(error)) {
1135+
const executionResultFromError = error.executionResult
11461136
const logs = Array.isArray(executionResultFromError.logs) ? executionResultFromError.logs : []
11471137

11481138
errorResult = {

apps/sim/executor/execution/engine.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
PausePoint,
1414
ResumeStatus,
1515
} from '@/executor/types'
16-
import { normalizeError } from '@/executor/utils/errors'
16+
import { attachExecutionResult, normalizeError } from '@/executor/utils/errors'
1717

1818
const logger = createLogger('ExecutionEngine')
1919

@@ -170,8 +170,8 @@ export class ExecutionEngine {
170170
metadata: this.context.metadata,
171171
}
172172

173-
if (error && typeof error === 'object') {
174-
;(error as any).executionResult = executionResult
173+
if (error instanceof Error) {
174+
attachExecutionResult(error, executionResult)
175175
}
176176
throw error
177177
}

apps/sim/executor/handlers/workflow/workflow-handler.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {
1111
ExecutionResult,
1212
StreamingExecution,
1313
} from '@/executor/types'
14+
import { hasExecutionResult } from '@/executor/utils/errors'
1415
import { buildAPIUrl, buildAuthHeaders } from '@/executor/utils/http'
1516
import { parseJSON } from '@/executor/utils/json'
1617
import { lazyCleanupInputMapping } from '@/executor/utils/lazy-cleanup'
@@ -148,8 +149,9 @@ export class WorkflowBlockHandler implements BlockHandler {
148149
const originalError = error.message || 'Unknown error'
149150
let childTraceSpans: WorkflowTraceSpan[] = []
150151
let executionResult: ExecutionResult | undefined
151-
if (error.executionResult?.logs) {
152-
executionResult = error.executionResult as ExecutionResult
152+
153+
if (hasExecutionResult(error) && error.executionResult.logs) {
154+
executionResult = error.executionResult
153155

154156
logger.info(`Extracting child trace spans from error.executionResult`, {
155157
hasLogs: (executionResult.logs?.length ?? 0) > 0,

apps/sim/executor/utils/errors.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
1-
import type { ExecutionContext } from '@/executor/types'
1+
import type { ExecutionContext, ExecutionResult } from '@/executor/types'
22
import type { SerializedBlock } from '@/serializer/types'
33

4+
/**
5+
* Interface for errors that carry an ExecutionResult.
6+
* Used when workflow execution fails and we want to preserve partial results.
7+
*/
8+
export interface ErrorWithExecutionResult extends Error {
9+
executionResult: ExecutionResult
10+
}
11+
12+
/**
13+
* Type guard to check if an error carries an ExecutionResult.
14+
*/
15+
export function hasExecutionResult(error: unknown): error is ErrorWithExecutionResult {
16+
return (
17+
error instanceof Error &&
18+
'executionResult' in error &&
19+
error.executionResult != null &&
20+
typeof error.executionResult === 'object'
21+
)
22+
}
23+
24+
/**
25+
* Attaches an ExecutionResult to an error for propagation to parent workflows.
26+
*/
27+
export function attachExecutionResult(error: Error, executionResult: ExecutionResult): void {
28+
Object.assign(error, { executionResult })
29+
}
30+
431
export interface BlockExecutionErrorDetails {
532
block: SerializedBlock
633
error: Error | string

apps/sim/hooks/use-execution-stream.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,13 @@ export function useExecutionStream() {
100100
})
101101

102102
if (!response.ok) {
103-
const error = await response.json()
104-
throw new Error(error.error || 'Failed to start execution')
103+
const errorResponse = await response.json()
104+
const error = new Error(errorResponse.error || 'Failed to start execution')
105+
// Attach the execution result from server response for error handling
106+
if (errorResponse && typeof errorResponse === 'object') {
107+
Object.assign(error, { executionResult: errorResponse })
108+
}
109+
throw error
105110
}
106111

107112
if (!response.body) {

0 commit comments

Comments
 (0)