From 98f114ac0d1053c58d2dc5838138fae66ce3e96a Mon Sep 17 00:00:00 2001 From: Brian Love Date: Thu, 21 May 2026 13:40:33 -0700 Subject: [PATCH] diag(minting): include err.cause + PG fields in webhook 500 body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TEMP smoke diagnostic — extends prior patch to include err.cause (postgres-js wraps the driver error under "Failed query:") plus PG fields (code, severity, detail, etc.) so we can see the actual cause of the processed_events insert failure. Revert after smoke. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../handlers/stripe-webhook.ts | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/minting-service/handlers/stripe-webhook.ts b/apps/minting-service/handlers/stripe-webhook.ts index ccafc821..346350e2 100644 --- a/apps/minting-service/handlers/stripe-webhook.ts +++ b/apps/minting-service/handlers/stripe-webhook.ts @@ -71,12 +71,23 @@ export default async function handler(req: VercelRequest, res: VercelResponse): await handleEvent(event, deps); res.status(200).json({ received: true }); } catch (err) { - const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err); - const stack = err instanceof Error ? (err.stack ?? '').split('\n').slice(0, 5).join(' | ') : ''; + const describe = (e: unknown): string => { + if (!(e instanceof Error)) return String(e); + const props = ['code', 'severity', 'detail', 'hint', 'where', 'schema_name', 'table_name', 'constraint_name', 'routine'] + .map((k) => { + const v = (e as unknown as Record)[k]; + return v === undefined ? null : `${k}=${String(v)}`; + }) + .filter((s): s is string => s !== null) + .join(' '); + const stack = (e.stack ?? '').split('\n').slice(0, 8).join(' | '); + return `${e.name}: ${e.message}${props ? ` [${props}]` : ''}\n ${stack}`; + }; + const top = describe(err); + const cause = err instanceof Error && err.cause ? `\nCAUSE: ${describe(err.cause)}` : ''; console.error('webhook handler error', { eventId: event.id, type: event.type, err }); - // TEMP smoke diagnostic — surface error class + message + first stack frames so - // we can read it via curl/Stripe Dashboard delivery body. Revert after smoke. - res.status(500).send(`internal error: ${msg}\n${stack}`); + // TEMP smoke diagnostic — surface error class + message + cause chain + PG fields. + res.status(500).send(`internal error: ${top}${cause}`); } finally { await db.close(); }