drizzle-team / drizzle-team/drizzle-orm

[FEATURE]: Error handling is not good in drizzle (Error hanlding capability)

Open
#4,660 5 comments 10 reactions 1 assignee Claimed by @AndriiSherman View on GitHub
enhancement
Dominant language
TypeScript
Stars
35.8k
Forks
1.6k
Avg merge
2d 7h
Merged PRs (30d)
4

Description

### Feature hasn't been suggested before.

- [x] I have verified this feature I'm about to request hasn't been suggested before.

### Describe the enhancement you want to request

i am a fan of drizzle and love it due to its simplicty but errors the way drizzle throws error is really heactic sometime i nned to write so many handling functions based on scenerio that also i feel not perfect because i am knew to drizzle

this is what i wrote

```typescript
import { InternalServerError } from './error';

// Format any Drizzle/PG error into a readable message
export function formatDrizzleError(err: any): string {
if (!err || typeof err !== 'object') {
return 'An unknown database error occurred.';
}

const pgError = extractOriginalPgError(err);

const code = pgError?.code;
const detail = pgError?.detail ?? '';
const constraint = pgError?.constraint ?? '';
const column = pgError?.column ?? '';
const rawMsg = pgError?.message ?? '';

switch (code) {
case '23505': // unique_violation
return `Duplicate value error: ${parseConstraint(constraint) || detail || 'a unique field already exists.'}`;

case '23503': // foreign_key_violation
return `Foreign key violation: ${parseConstraint(constraint) || detail || 'referenced record not found.'}`;

case '23502': // not_null_violation
return `Missing required field: ${column || parseColumnFromMessage(rawMsg) || 'a required field was missing.'}`;

case '22P02': // invalid_text_representation
return `Invalid data format: ${detail || 'Check input types and formats.'}`;

default:
return `Database error${code ? ` [${code}]` : ''}: ${stripQuery(rawMsg) || 'Unexpected database error.'}`;
}
}

// Extracts underlying PG error from Drizzle's wrapped error
function extractOriginalPgError(err: any): any {
if (err?.cause && typeof err.cause === 'object') return err.cause;
return err;
}

// Dynamically parse constraint name into human-readable message
function parseConstraint(constraint: string): string {
if (!constraint) return 'A database constraint was violated.';

const fieldMatch = constraint.match(/_(\w+?)(?:_key|_idx|_fkey)?$/);
const field = fieldMatch?.[1];
const prettyField = field ? toTitleCase(field.replace(/_/g, ' ')) : null;

if (constraint.includes('_key'))
return `${prettyField ?? constraint} must be unique.`;
if (constraint.includes('_fkey'))
return `${prettyField ?? constraint} must reference a valid record.`;

return `Constraint violation on ${prettyField ?? constraint}.`;
}

// Converts snake_case to Title Case
function toTitleCase(str: string): string {
return str
.split(' ')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}

// Parses column name from a NOT NULL violation message
function parseColumnFromMessage(msg: string): string | null {
const match = msg.match(/null value in column "(.*?)"/);
return match ? match[1] : null;
}

// Clean up noisy raw SQL messages
function stripQuery(msg: string): string {
if (!msg) return '';
return msg
.split('\n')[0] // Only keep the first line
.replace(/^Failed query:\s*/, '')
.trim();
}

// Function wrapper to catch and rethrow with formatted error
export function withErrorHandling Promise>(
fn: T,
): T {
return (async (...args: Parameters): Promise> => {
try {
return await fn(...args);
} catch (err: any) {
const message = formatDrizzleError(err);
console.error('🚨 Database Error:', message);
throw new InternalServerError(message);
}
}) as T;
}

```

i request you to please add something which help in error handling in production

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.