Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion apps/sim/lib/workflows/executor/execution-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { filterUndefined } from '@sim/utils/object'
import { mergeSubblockStateWithValues } from '@sim/workflow-persistence/subblocks'
import type { Edge } from 'reactflow'
import { z } from 'zod'
Expand Down Expand Up @@ -39,6 +40,49 @@ const logger = createLogger('ExecutionCore')

const EnvVarsSchema = z.record(z.string(), z.string())

/**
* Surfaces the underlying driver error from a wrapped error chain.
*
* Drizzle wraps the original `postgres`/Node driver error as `error.cause`,
* which the logger's Error serializer drops (it only emits own-enumerable
* keys). Walking the chain from `error` itself and preferring the first error
* carrying a `code` exposes the diagnostic fields — notably the Postgres
* `code` — that distinguish a connection drop (`08006`), a rejected connection
* (`53300`), and a statement timeout (`57014`) behind an opaque "Failed query"
* message. Starting at `error` also captures a bare driver error that reaches
* this path unwrapped; when no error in the chain carries a `code`, it falls
* back to the first wrapped cause (the top-level error is already logged on its
* own, so it is not echoed here).
*/
function describeErrorCause(error: unknown): Record<string, unknown> | undefined {
try {
let driver: (Error & Record<string, unknown>) | undefined
let current: unknown = error
for (let depth = 0; depth < 10 && current instanceof Error; depth++) {
const candidate = current as Error & Record<string, unknown>
if (candidate.code !== undefined) {
driver = candidate
break
}
if (depth === 1) driver = candidate
current = candidate.cause
}
if (!driver) return undefined
return filterUndefined({
name: driver.name,
message: driver.message,
code: driver.code,
severity: driver.severity,
detail: driver.detail,
routine: driver.routine,
errno: driver.errno,
syscall: driver.syscall,
})
} catch {
return undefined
}
}
Comment thread
TheodoreSpeaks marked this conversation as resolved.

export interface ExecuteWorkflowCoreOptions {
snapshot: ExecutionSnapshot
callbacks: ExecutionCallbacks
Expand Down Expand Up @@ -682,7 +726,12 @@ export async function executeWorkflowCore(

return result
} catch (error: unknown) {
logger.error(`[${requestId}] Execution failed:`, error)
const errorCause = describeErrorCause(error)
logger.error(
`[${requestId}] Execution failed:`,
error,
...(errorCause ? [{ cause: errorCause }] : [])
)

await waitForLifecycleCallbacks()

Expand Down
Loading