From df525d4369979a8f6da99218572bc22cd0fabb34 Mon Sep 17 00:00:00 2001 From: Jake Bromberg Date: Wed, 20 May 2026 15:16:18 -0700 Subject: [PATCH 1/2] fix(library-identity-consumer): log error.cause on writer failure so PG diagnostics surface Drizzle wraps every postgres-js failure in DrizzleQueryError, whose .message is hardcoded to "Failed query: \nparams: ". The actual PG error (code, detail, constraint_name, column_name) lives on .cause. The orchestrator's catch block only captured (error as Error).message, producing 14,405 identical "Failed query" log lines during the 2026-05-20 first prod run with no PG diagnostic. Surface .cause's standard PostgresError properties on the warn log line so failures are debuggable without a manual psql repro. Field shape mirrors postgres-js's PostgresError (pg_message, pg_code, pg_detail, pg_constraint, pg_column, pg_table, pg_routine). --- jobs/library-identity-consumer/orchestrate.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/jobs/library-identity-consumer/orchestrate.ts b/jobs/library-identity-consumer/orchestrate.ts index 007d5305..caacc9ed 100644 --- a/jobs/library-identity-consumer/orchestrate.ts +++ b/jobs/library-identity-consumer/orchestrate.ts @@ -225,9 +225,27 @@ export const runConsumer = async (opts: { totals.rows_resolved += 1; totals.source_rows_skipped_null_confidence += outcome.source_rows_skipped_null_confidence; } catch (error) { + // Drizzle wraps every postgres-js failure in DrizzleQueryError, whose + // `.message` is hardcoded to "Failed query: \nparams: ". + // The actual PG error (code, detail, constraint_name, column_name) lives + // on `.cause`. Logging only `.message` produced a fleet of identical + // "Failed query" log lines during the 2026-05-20 first run with no PG + // diagnostic — surfacing both makes failures debuggable without a manual + // psql repro. + const err = error as { message?: string; cause?: unknown }; + const cause = err.cause as + | { message?: string; code?: string; detail?: string; constraint_name?: string; column_name?: string; table_name?: string; routine?: string } + | undefined; log('warn', 'writer_error', `writer failed for library_id=${result.library_id}`, { library_id: result.library_id, - error_message: (error as Error).message, + error_message: err.message, + pg_message: cause?.message, + pg_code: cause?.code, + pg_detail: cause?.detail, + pg_constraint: cause?.constraint_name, + pg_column: cause?.column_name, + pg_table: cause?.table_name, + pg_routine: cause?.routine, }); captureError(error, 'writer_error', { library_id: result.library_id }); totals.rows_skipped.writer_error += 1; From c0863d5cd7d6b33816cf77c07a10295e911474a5 Mon Sep 17 00:00:00 2001 From: Jake Bromberg Date: Wed, 20 May 2026 15:56:22 -0700 Subject: [PATCH 2/2] fix(library-identity-consumer): satisfy prettier + fallback when err.message missing - Re-flow the cause type annotation per prettier (CI format:check was failing) - error_message falls back to String(error) for non-Error throws --- jobs/library-identity-consumer/orchestrate.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/jobs/library-identity-consumer/orchestrate.ts b/jobs/library-identity-consumer/orchestrate.ts index caacc9ed..6e32b4d9 100644 --- a/jobs/library-identity-consumer/orchestrate.ts +++ b/jobs/library-identity-consumer/orchestrate.ts @@ -234,11 +234,19 @@ export const runConsumer = async (opts: { // psql repro. const err = error as { message?: string; cause?: unknown }; const cause = err.cause as - | { message?: string; code?: string; detail?: string; constraint_name?: string; column_name?: string; table_name?: string; routine?: string } + | { + message?: string; + code?: string; + detail?: string; + constraint_name?: string; + column_name?: string; + table_name?: string; + routine?: string; + } | undefined; log('warn', 'writer_error', `writer failed for library_id=${result.library_id}`, { library_id: result.library_id, - error_message: err.message, + error_message: err.message ?? String(error), pg_message: cause?.message, pg_code: cause?.code, pg_detail: cause?.detail,