Bug report
Describe the bug
Calling supabase.auth.signInWithOtp() from a SvelteKit form action, using the standard SvelteKit SSR cookie-handling pattern documented at https://supabase.com/docs/guides/auth/server-side/creating-a-client, throws a 500 error:
Error: "Cache-Control" header is already set at Object.setHeaders (node_modules/@sveltejs/kit/src/runtime/server/respond.js) at setAll (src/hooks.server.ts) at applyServerStorage (node_modules/@supabase/ssr/dist/main/cookies.js) at async Object.setItem (node_modules/@supabase/ssr/dist/main/cookies.js) at async setItemAsync (node_modules/@supabase/auth-js/dist/main/lib/helpers.js) at async storePKCEVerifier (node_modules/@supabase/auth-js/dist/main/lib/helpers.js) at async getCodeChallengeAndMethod (node_modules/@supabase/auth-js/dist/main/lib/helpers.js) at async SupabaseAuthClient.signInWithOtp (node_modules/@supabase/auth-js/dist/main/GoTrueClient.js)
Root cause appears to be: storing the PKCE code verifier during signInWithOtp() invokes the setAll cookie callback, which calls event.setHeaders(headers) with a Cache-Control header (per @supabase/ssr's own documented behavior of attaching cache-prevention headers to cookie-writing calls). This callback gets invoked more than once within the single signInWithOtp() call. SvelteKit's event.setHeaders() throws if called twice with the same header name in one request — unlike, e.g., a plain Headers.set(), which would just overwrite silently. So this specific combination (SvelteKit's stricter header API + @supabase/ssr calling the headers callback multiple times per auth operation) crashes.
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
- Set up SvelteKit with @supabase/ssr, following the exact hooks.server.ts pattern from the official docs (createServerClient with getAll/setAll, calling event.setHeaders(headers) inside setAll).
- Call supabase.auth.signInWithOtp({ email }) from a form action using the request-scoped server client from event.locals.
- Submit the form.
- See 500 error / stack trace above.
Expected behavior
signInWithOtp() (or any auth method that triggers cookie/header writes as a side effect, e.g. PKCE verifier storage) should not cause the setAll headers argument to be applied more than once per header name within a single request — either by not invoking the headers callback redundantly, or by documenting that consuming frameworks with strict single-set header semantics (like SvelteKit) need to dedupe headers themselves in their setAll implementation.
System information
- OS: macOS
- Version of supabase-js: 2.111.0
- Version of @supabase/ssr: 0.12.4 (latest as of testing)
- Version of Node.js: v25.2.1
- SvelteKit: 2.70.2
Additional context
Related to a similar class of issue: #144 (duplicate Set-Cookie/header calls per request), though that issue concerns multiple client instances in one request, whereas this occurs with a single client instance during a single signInWithOtp() call.
Bug report
Describe the bug
Calling supabase.auth.signInWithOtp() from a SvelteKit form action, using the standard SvelteKit SSR cookie-handling pattern documented at https://supabase.com/docs/guides/auth/server-side/creating-a-client, throws a 500 error:
Error: "Cache-Control" header is already set at Object.setHeaders (node_modules/@sveltejs/kit/src/runtime/server/respond.js) at setAll (src/hooks.server.ts) at applyServerStorage (node_modules/@supabase/ssr/dist/main/cookies.js) at async Object.setItem (node_modules/@supabase/ssr/dist/main/cookies.js) at async setItemAsync (node_modules/@supabase/auth-js/dist/main/lib/helpers.js) at async storePKCEVerifier (node_modules/@supabase/auth-js/dist/main/lib/helpers.js) at async getCodeChallengeAndMethod (node_modules/@supabase/auth-js/dist/main/lib/helpers.js) at async SupabaseAuthClient.signInWithOtp (node_modules/@supabase/auth-js/dist/main/GoTrueClient.js)Root cause appears to be: storing the PKCE code verifier during signInWithOtp() invokes the setAll cookie callback, which calls event.setHeaders(headers) with a Cache-Control header (per @supabase/ssr's own documented behavior of attaching cache-prevention headers to cookie-writing calls). This callback gets invoked more than once within the single signInWithOtp() call. SvelteKit's event.setHeaders() throws if called twice with the same header name in one request — unlike, e.g., a plain Headers.set(), which would just overwrite silently. So this specific combination (SvelteKit's stricter header API + @supabase/ssr calling the headers callback multiple times per auth operation) crashes.
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
Expected behavior
signInWithOtp() (or any auth method that triggers cookie/header writes as a side effect, e.g. PKCE verifier storage) should not cause the setAll headers argument to be applied more than once per header name within a single request — either by not invoking the headers callback redundantly, or by documenting that consuming frameworks with strict single-set header semantics (like SvelteKit) need to dedupe headers themselves in their setAll implementation.
System information
Additional context
Related to a similar class of issue: #144 (duplicate Set-Cookie/header calls per request), though that issue concerns multiple client instances in one request, whereas this occurs with a single client instance during a single signInWithOtp() call.