Always Check Error Before Using Data from Supabase Queries
Share
Destructuring { data } without checking { error } from Supabase queries ignores failures silently. When error is non-null, data is always null. [CWE-252]
Why This Matters
prevents silent failures and null reference crashes in production
Always Check Error Before Using Data from Supabase Queries
Impact: HIGH (prevents silent failures and null reference crashes in production)
Every Supabase query returns { data, error }. When error is non-null, data is alwaysnull. Destructuring only { data } and using it without checking error leads to TypeError: Cannot read properties of null at runtime. These crashes are especially hard to diagnose because the actual cause (RLS violation, network timeout, invalid column) is silently discarded.
This is the Supabase equivalent of unchecked return values — the query failed, but your code proceeds as if it succeeded.
Incorrect (ignoring error entirely):
// ❌ Destructures data without checking errorexport default async function DashboardPage() { const supabase = await createClient() const { data: projects } = await supabase .from('projects') .select('id, name, created_at') .order('created_at', { ascending: false }) // ❌ If query fails (RLS, network, typo in table name), projects is null // This crashes with: TypeError: Cannot read properties of null (reading 'map') return ( <ul> {projects.map((project) => ( <li key={project.id}>{project.name}</li> ))} </ul> )}
Incorrect (checking error but continuing to use data):
// ❌ Logs error but still uses data (which is null)export async function GET() { const supabase = await createClient() const { data, error } = await supabase .from('projects') .select('*') if (error) { console.warn('Query had an error:', error.message) // ❌ Falls through — data is null below } // ❌ data is null when error is non-null return Response.json({ projects: data }) // Returns { projects: null }}
Incorrect (optional chaining hides the real problem):
// ❌ Optional chaining silences the error but shows blank UIconst { data: profile } = await supabase .from('profiles') .select('display_name, avatar_url') .eq('id', userId) .single()// User sees "Unknown" with default avatar — no indication of failurereturn ( <div> <h1>{profile?.display_name ?? 'Unknown'}</h1> <img src={profile?.avatar_url ?? '/default.png'} /> </div>)
Correct (check error and return early in Server Components):
// ✅ Check error before using dataexport default async function DashboardPage() { const supabase = await createClient() const { data: projects, error } = await supabase .from('projects') .select('id, name, created_at') .order('created_at', { ascending: false }) if (error) { // ✅ Log for debugging, throw for error boundary console.error('Projects query failed:', { code: error.code, message: error.message }) throw new Error('Failed to load projects') } // ✅ TypeScript narrows: projects is non-null here return ( <ul> {projects.map((project) => ( <li key={project.id}>{project.name}</li> ))} </ul> )}