Skip to content

@supabase/ssr browser client auth methods hang indefinitely due to orphaned Web Locks #2111

@WillTaylor22

Description

@WillTaylor22

@supabase/ssr browser client auth methods hang indefinitely due to orphaned Web Locks (potentially React Strict Mode compatibility issue)

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

Description

(N.b. - written with AI but it's done a far more comprehensive job than I would have - hope that's OK)

The @supabase/ssr browser client's auth methods (getUser(), signInWithPassword(), etc.) hang indefinitely without making any network requests when a Web Lock from a previous auth operation is not properly released.

The Supabase auth client uses the browser's Web Locks API (navigator.locks) to prevent concurrent auth operations. When a lock is acquired but not released (e.g., due to React Strict Mode unmounting a component mid-operation, or an abort signal firing), all subsequent auth calls queue behind the orphaned lock and hang forever.

The error AbortError: signal is aborted without reason appears in the console from locks.ts, indicating the lock acquisition was aborted, but the lock remains held.

To Reproduce

  1. Create a Next.js 14+ app with @supabase/ssr (React Strict Mode is enabled by default)
  2. Create a client component that calls supabase.auth.getUser() in a useEffect:
"use client";
import { useEffect } from "react";
import { createClient } from "@/lib/supabase/client"; // uses createBrowserClient

export default function SettingsPage() {
  const supabase = createClient();

  useEffect(() => {
    const fetchUser = async () => {
      const {
        data: { user },
      } = await supabase.auth.getUser(); // Hangs here
      console.log(user);
    };
    fetchUser();
  }, [supabase]);

  return <div>Settings</div>;
}
  1. Navigate to the page - it may work initially
  2. Trigger React Strict Mode's unmount/remount cycle (happens automatically in dev) or navigate away while auth is in progress
  3. Subsequent auth calls hang indefinitely

Verification: Run in browser console:

navigator.locks.query().then(console.log);

You'll see:

{
  held: [{ name: "lock:sb-xxx-auth-token", mode: "exclusive" }],
  pending: [{ name: "lock:sb-xxx-auth-token", mode: "exclusive" }]
}

A lock is held and never released, with pending requests queued behind it.

Expected behavior

  1. Auth methods should complete or fail within a reasonable timeout, not hang indefinitely
  2. If a lock acquisition is aborted (e.g., component unmount), the lock should be properly released
  3. The auth client should be resilient to React Strict Mode's double-mount behavior in development

System information

  • OS: macOS 15.7
  • Browser: Chrome 144.0.7559.112
  • Version of @supabase/ssr: 0.8.0
  • Version of @supabase/supabase-js: 2.86.0
  • Version of Node.js: (Next.js 14+)
  • React: 18+ with Strict Mode enabled (Next.js default)

Additional context

Workaround: Close the browser completely to release orphaned locks, then reopen.

HAR file evidence: Network capture shows zero requests to Supabase auth endpoints when the hang occurs - the client is stuck internally waiting for the Web Lock, not waiting for a network response.

Related: This may be related to how @supabase/gotrue-js handles AbortController signals in locks.ts. When the abort fires, the lock holder should release the lock, but it appears the lock remains held.

Potential fixes:

  1. Add a timeout to lock acquisition that releases the lock and throws an error
  2. Use navigator.locks.request() with { steal: true } option to force-acquire stuck locks
  3. Better handling of React Strict Mode's component lifecycle (mount → unmount → remount)
  4. Add a forceUnlock() method or automatic recovery mechanism

Metadata

Metadata

Assignees

Labels

auth-jsRelated to the auth-js library.bugSomething isn't workingretry with latestUsers should retry with latest version of the SDK.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions