Treating all Supabase errors the same (if error, throw) hides whether a record is missing or the query itself failed. Check error codes for proper handling.
Why This Matters
prevents masking 404s as 500s and enables proper error recovery
Impact: MEDIUM (prevents masking 404s as 500s and enables proper error recovery)
Supabase queries can fail for many reasons: network errors, RLS violations, invalid column names, constraint violations, or simply "no rows found." Treating all errors identically with if (error) throw error masks the difference between a missing record (expected, recoverable) and a query failure (unexpected, needs investigation).
PostgREST uses specific error codes that you can check to distinguish these cases. The most important is PGRST116 — "no rows returned" when using .single() or .maybeSingle().
Incorrect (treating all errors the same):
// ❌ Treats "not found" the same as "database down"async function getProject(projectId: string) { const supabase = await createClient() const { data, error } = await supabase .from('projects') .select('id, name, status') .eq('id', projectId) .single() if (error) { // ❌ This could be: // - PGRST116: No rows found (project doesn't exist) → should return 404 // - 42501: RLS violation (user can't access) → should return 403 // - 42P01: Table doesn't exist (bug) → should return 500 // - Network error → should retry or return 503 throw error // All become the same generic error } return data}
// ❌ Catching errors with a generic messageexport async function GET( request: Request, { params }: { params: { id: string } }) { const supabase = await createClient() const { data, error } = await supabase .from('projects') .select('*') .eq('id', params.id) .single() if (error) { // ❌ Returns 500 even when the project simply doesn't exist return Response.json({ error: 'Something went wrong' }, { status: 500 }) } return Response.json(data)}
Correct (check error codes for proper handling):
// ✅ Handle different error types appropriatelyasync function getProject(projectId: string) { const supabase = await createClient() const { data, error } = await supabase .from('projects') .select('id, name, status, created_at') .eq('id', projectId) .single() if (error) { // Not found — record doesn't exist or RLS hides it if (error.code === 'PGRST116') { return null // Caller can handle missing project } // All other errors are unexpected — log and throw console.error('Failed to fetch project:', { code: error.code, message: error.message, projectId, }) throw new Error('Failed to load project') } return data}
Correct (ServiceResult pattern for typed error handling):