From 81aa8d066bf935c49d4821c2c0c3d1834d7da67d Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Tue, 26 May 2026 16:36:36 -0700 Subject: [PATCH] log(db): Add db failure cause log message --- .../lib/workflows/executor/execution-core.ts | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/apps/sim/lib/workflows/executor/execution-core.ts b/apps/sim/lib/workflows/executor/execution-core.ts index bffc4d4c86..7fb35a4910 100644 --- a/apps/sim/lib/workflows/executor/execution-core.ts +++ b/apps/sim/lib/workflows/executor/execution-core.ts @@ -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' @@ -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 | undefined { + try { + let driver: (Error & Record) | undefined + let current: unknown = error + for (let depth = 0; depth < 10 && current instanceof Error; depth++) { + const candidate = current as Error & Record + 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 + } +} + export interface ExecuteWorkflowCoreOptions { snapshot: ExecutionSnapshot callbacks: ExecutionCallbacks @@ -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()