Skip to content

GoTrueClient uses infinite timeouts for lock acquisition causing deadlocks in production #1594

@dtinth

Description

@dtinth

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

I encountered a situation where Supabase Auth never finish initializing.

  • The impact on my app is that it never finishes initializing and any auth operation hangs.

  • I already checked that onAuthStateChange is not async and doesn't call any Supabase API, so #762 doesn't apply.

  • The GoTrueClient initialization hangs indefinitely on some devices (in my case, Chrome Android) due to a lack of timeouts in the Web Locks API implementation.

  • I investigated this by digging into the source code and enabling the undocumented debug option. On the affected device, the #_acquireLock call never resolved

    On a working device, the debug log is normal On a problematic device, it got stuck at #_acquireLock
    Image Image

    Additionally, on a problematic device, checking supabase.auth.initializePromise returns a never-resolving promise.

  • It seems that a previous lock wasn't properly released… when I run await navigator.locks.query() I see that some locks are being held indefinitely.

    Held locks
    Image
  • Is it really a good idea to wait for a lock indefinitely?? Sorry if I sound frustrated, but I kinda am – I just paid for Supabase Pro and didn't expect this from a professional auth solution. I kinda spent an hour scratching my head figuring out what's wrong with my app. That said, I really appreciate the overall quality of Supabase and believe this is just an edge case to be fixed. I hope this investgation will be useful.

To Reproduce

This issue is not easily reproducible as it appears to be race condition or environment-dependent. However, it occurs in production on real devices where users experience complete authentication failure.

The fundamental issue is that the current implementation holds Web Locks indefinitely without a timeout, which violates basic concurrency principles. Any scenario that prevents proper lock cleanup can trigger this deadlock.

Expected behavior

Supabase Auth should be able to recover from a situation where the lock is not properly released. The lock mechanism should have a timeout and fallback to ensure the client doesn't hang indefinitely.

Currently, the there is no acquireTimeout (-1 means no timeout):

https://github.com/supabase/auth-js/blob/aadf02e63179746a06451f4247a370dfd05740ea/src/GoTrueClient.ts#L358-L362

Maybe it should be set to some sane value, like maybe 1 minute.

Screenshots

The app doesn't launch as Auth never finished initializing, and User sees a white page.
Image

System information

  • OS: Android
  • Browser: Chrome
  • Version of supabase-js: 2.71.1
  • Affected code: @supabase/auth-js GoTrueClient

Additional context

Current workaround

Until a proper lease is implemented, I am currently working around this issue by specifying a noOpLock when initializing Supabase. However I don’t know what might go wrong if we skip the locks.

const noOpLock = async (name: string, acquireTimeout: number, fn: () => Promise<any>) => {
  return await fn()
}

const supabase = createClient(url, key, {
  auth: { lock: noOpLock }
})

Debug session and debug log

Checking the locks in JS Console

await navigator.locks.query()

{
  held: [
    {clientId: '0ccb43ce-27c2-423e-8cbe-63a9c2da37b4', mode: 'exclusive', name: 'lock:sb-nmzhiwafofgwvqucnbds-auth-token'}
  ],
  pending: [
    {clientId: '0ccb43ce-27c2-423e-8cbe-63a9c2da37b4', mode: 'exclusive', name: 'lock:sb-nmzhiwafofgwvqucnbds-auth-token'},
    {clientId: 'e6ee664e-e2d9-4f1d-8a9a-0ab0b5e83ee6', mode: 'exclusive', name: 'lock:sb-nmzhiwafofgwvqucnbds-auth-token'},
    {clientId: 'e6ee664e-e2d9-4f1d-8a9a-0ab0b5e83ee6', mode: 'exclusive', name: 'lock:sb-nmzhiwafofgwvqucnbds-auth-token'},
    {clientId: '9d09c2ce-ac43-4783-b356-e988cae6bc26', mode: 'exclusive', name: 'lock:sb-nmzhiwafofgwvqucnbds-auth-token'}
  ]
}

Debug logs showing the hang:

GoTrueClient@0 (2.71.1) 2025-09-13T19:24:55.355Z #_acquireLock begin -1
GoTrueClient@0 (2.71.1) 2025-09-13T19:24:55.355Z #onAuthStateChange() registered callback with id a5571c4b-9f69-4111-b314-119f2e0ecb87
(hangs here - never proceeds to lock acquisition)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions