Error Handling Examples
These examples demonstrate proper error handling patterns with database operations.
Referenced by: best-practices.md, patterns.md
Example 1: Basic Error Handling
import { withClient } from '@/lib/db';
import { createResource } from '@db/graph';
import { ZodError } from 'zod';
try {
const id = await withClient(async (client) => {
return await createResource(client, {
p_type_namespace: userInput,
p_external_id: externalId,
p_data: untrustedData
});
});
} catch (error) {
if (error instanceof ZodError) {
// Validation error
console.error('Validation error:', error.errors);
throw new ValidationError('Invalid input', error.errors);
} else if (error.code === '23505') {
// PostgreSQL unique violation
console.error('Duplicate entry');
throw new DuplicateError('Resource already exists');
} else {
// Other database error
console.error('Database error:', error);
throw new DatabaseError('Operation failed');
}
}
Example 2: Handling Duplicate External ID
import { test } from '@/test-utils-integration/config/database.context';
import { createResource } from '@db/graph';
test('handles duplicate external_id', async ({ newDbClient }) => {
// Create first resource
await createResource(newDbClient, {
p_type_namespace: 'test.type',
p_external_id: 'duplicate'
});
// Attempt to create duplicate
await expect(
createResource(newDbClient, {
p_type_namespace: 'test.type',
p_external_id: 'duplicate'
})
).rejects.toThrow(/already exists/);
});
Example 3: PostgreSQL Error Codes
import { withClient } from '@/lib/db';
try {
await withClient(async (client) => {
return await client.query('INSERT INTO ...');
});
} catch (error) {
switch (error.code) {
case '23505':
// unique_violation
throw new Error('Duplicate entry');
case '23503':
// foreign_key_violation
throw new Error('Referenced record does not exist');
case '23502':
// not_null_violation
throw new Error('Required field missing');
case '40001':
// serialization_failure
throw new Error('Transaction conflict, retry');
default:
throw new Error(`Database error: ${error.message}`);
}
}
Example 4: Validation Error Details
import { createResource } from '@db/graph';
import { ZodError } from 'zod';
try {
await createResource(client, {
p_type_namespace: 'invalid type',
p_data: 'not an object'
});
} catch (error) {
if (error instanceof ZodError) {
// Get detailed validation errors
const errors = error.errors.map(err => ({
path: err.path.join('.'),
message: err.message,
code: err.code
}));
console.error('Validation failed:', errors);
// [
// { path: 'p_type_namespace', message: 'Invalid format', code: 'custom' },
// { path: 'p_data', message: 'Expected object', code: 'invalid_type' }
// ]
}
}
Example 5: Graceful Degradation
import { withClient } from '@/lib/db';
import { createResource } from '@db/graph';
async function createResourceWithFallback(data: ResourceData) {
try {
return await withClient(async (client) => {
return await createResource(client, {
p_type_namespace: data.type,
p_external_id: data.id,
p_data: data.attributes
});
});
} catch (error) {
if (error.code === '23505') {
// Already exists, fetch existing
console.warn('Resource exists, fetching existing');
return await withClient(async (client) => {
const resources = await getResource(client, {
p_type_namespace: data.type,
p_external_id: data.id
});
return resources[0].id;
});
}
throw error;
}
}