From 4de6b7719ed20c97292b87f99a0c438e217285fb Mon Sep 17 00:00:00 2001 From: Arnas Donauskas Date: Thu, 16 Apr 2026 19:39:24 +0300 Subject: [PATCH] fix: make Supabase browser client a singleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes two runtime errors: 1. "Lock 'lock:sb-xxx-auth-token' was released because another request stole it" — caused by multiple Supabase client instances competing for the same auth storage lock. 2. "Failed to fetch conversations: {}" — related to #1. When the auth lock is stolen mid-request, the session becomes temporarily unavailable and queries fail. The codebase had 65 call sites invoking createClient() — each creating a new browser client with its own auth listener. This change makes createClient() cache and return a single shared instance. Also improved error logging in conversation-list.tsx to show Supabase error fields (message/details/hint/code) instead of an empty {}. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/inbox/conversation-list.tsx | 8 +++++++- src/lib/supabase/client.ts | 12 +++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/inbox/conversation-list.tsx b/src/components/inbox/conversation-list.tsx index 76c6ee6..c13e137 100644 --- a/src/components/inbox/conversation-list.tsx +++ b/src/components/inbox/conversation-list.tsx @@ -54,7 +54,13 @@ export function ConversationList({ .order("last_message_at", { ascending: false }); if (error) { - console.error("Failed to fetch conversations:", error); + // Supabase errors have non-enumerable properties — log fields explicitly + console.error("Failed to fetch conversations:", { + message: error.message, + details: error.details, + hint: error.hint, + code: error.code, + }); setLoading(false); return; } diff --git a/src/lib/supabase/client.ts b/src/lib/supabase/client.ts index 792b457..f381eb7 100644 --- a/src/lib/supabase/client.ts +++ b/src/lib/supabase/client.ts @@ -1,8 +1,18 @@ import { createBrowserClient } from '@supabase/ssr' +import type { SupabaseClient } from '@supabase/supabase-js' + +// Singleton instance — one client shared across the whole browser session. +// Creating multiple clients causes auth-lock contention ("Lock was released +// because another request stole it") and intermittent fetch failures. +let browserClient: SupabaseClient | undefined export function createClient() { - return createBrowserClient( + if (browserClient) return browserClient + + browserClient = createBrowserClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! ) + + return browserClient }