drizzle-team / drizzle-team/drizzle-orm
[FEATURE]: Error handling is not good in drizzle (Error hanlding capability)
- 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
Assessment
This issue has not been assessed yet.