fix(db): surface PG error code/detail/cause in voice recording insert failures

Drizzle wraps PG errors — the previous log only showed the formatted query
text. Now extracts code, detail, schema, table, constraint, severity from
the error envelope and from .cause to make the actual Postgres error visible.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-14 04:40:22 +07:00
co-authored by Claude
parent dbc2879e16
commit a2beda77c4
@@ -40,13 +40,35 @@ export async function insertVoiceRecording(
.values(recording)
.onConflictDoNothing();
} catch (error) {
const err = error as Record<string, unknown>;
// Drizzle wraps PG errors — dig into cause + enumerable props for the real PG error
const err = error as Error & Record<string, unknown>;
const detail: Record<string, unknown> = {
message: error instanceof Error ? error.message : String(error),
name: error instanceof Error ? error.name : undefined,
message: err.message,
name: err.name,
};
if (err.code !== undefined) detail.code = err.code;
if (err.detail !== undefined) detail.detail = err.detail;
// node-postgres native error props
for (const k of [
"code",
"detail",
"schema",
"table",
"constraint",
"severity",
]) {
if (err[k] !== undefined) detail[k] = err[k];
}
// drizzle may stash the original in .cause
const cause = err.cause;
if (cause instanceof Error) {
const causeErr = cause as Error & Record<string, unknown>;
detail.cause = {
message: causeErr.message,
name: causeErr.name,
code: causeErr.code,
detail: causeErr.detail,
constraint: causeErr.constraint,
};
}
logger.error(
{ id: recording.id, error: detail },
"Failed to insert voice recording",