auth-helpers: [SvelteKit] Error: Cannot use `cookies.set(...)` after the response has been generated
Bug report
Describe the bug
When using SvelteKit’s new streaming promises feature, it seems to run into an issue setting cookies with the logic that runs in server hooks mentioned here.
Here is the error:
Error: Cannot use `cookies.set(...)` after the response has been generated
at Object.event.cookies.set (/node_modules/@sveltejs/kit/src/runtime/server/respond.js:422:11)
at fetch (/node_modules/@sveltejs/kit/src/runtime/server/fetch.js:150:21)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Object.eval [as fetch] (/node_modules/@sveltejs/kit/src/runtime/server/fetch.js:32:10)
at async generateItinerary (/src/routes/(app)/trips/[tripId]/itinerary/+page.server.ts:7:22)
If I comment out all the logic in my hooks file, the error seems to go away, and the data from the streamed promise will return correctly.
Here is my +page.server.ts load function that is calling the API endpoint:
export const load = (async ({ parent, fetch, locals, params }) => {
const generateItinerary = async () => {
const response = await fetch('/api/itineraries/generate', {
method: 'POST',
body: JSON.stringify({
destination: 'Paris, France',
days: 1,
preferences: 'must-see attractions'
})
});
const data = await response.json(); <<< This is where it breaks
console.log('DATA: ', data); <<< This console log never happens due to the cookie error thrown
return data;
};
return {
lazy: {
itineraries: generateItinerary()
}
};
}) satisfies PageServerLoad;
The API endpoint itself returns fine, however when trying to utilize streaming promises, it seems to break. A regular top-level awaited promise will work as well. But with a streaming promise, it will run into the cookie error.
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
- Setup
hooks.server.tsas instructed according to Supabase docs - Create an API endpoint
- Create a layout or page server load function to fetch from API endpoint
- The load function will fail to return the data from the API endpoint, and error appears server console
Expected behavior
The load function should unwrap the streaming promise from the API endpoint and return the data.
Screenshots
If applicable, add screenshots to help explain your problem.
System information
- OS: macOS
- Version of supabase-js: v2.10.0
- Version of supabase-auth-helpers-sveltekit: v0.9.0
- Version of Node.js: v16.17.0
- Version of SvelteKit: v1.10.0
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 7
- Comments: 27
I’m still running into this issue when I updated to the SSR package. Here’s my versions: “@sveltejs/kit”: “^2.0.0”, “svelte”: “5.0.0-next.55”, “supabase”: “^1.145.4”, “@supabase/ssr”: “^0.1.0”, “@supabase/supabase-js”: “^2.39.2”,
Minimal reproduction
I have created a minimal, reproducible example for this error and carefully documented it in the README file. Hopefully, it serves useful in resolving the issue, as it’s currently blocking our production release.
I am able to reproduce this error with the example “Sveltekit Email password” with no changes. It is easier to reproduce when setting “JWT expiry limit” to 30 seconds.
Then navigate to the base path (“/”) via the link in the layout 30 seconds after you logged in.
From my testing it seems to be some issue with using load function in +page.ts file and having actions in +page.server.ts. When removing the +page.server.ts the error doesn’t appear.
https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit-email-password
When moving all load functions inside +page.server.ts and removing +page.ts, then it works.
Hi, just to add to this, I’m also getting same error. I’m unable to pin point where it’s coming from from exactly. Cannot reproduce it yet either. This is the error message:
I’ll be trying to consistently reproduce. It would be super helpful If you could point me to some direction. Thanks!
Thank you very much for the reproduction @rudgalvis !
I´ve been playing around with it and it seems like the supabase client isn´t actually used when navigating between
/postsand/auth. SvelteKit makes a request to the server and since there is a shared layout load function at the root that does all the work the response is basicly empty (just some sveltekit internal stuff telling the client it has all data). So what happens is that the client will be created in the handle hook and lazily callsgetSessionsome time in the future (no idea why tbh). I managed to create a workaround:This makes sure
getSessionis called before the response is created (the headers are sent).I´m not sure how we should actually make this work properly without this weird workaround, it feels like there is something missing to sveltekit like a simple boolean to check if the headers are already sent. I´ll think about it over the weekend but for the meantime the code snippet above should help you getting rid of the error.
Hi,
In case this helps anyone else out that lands here look for a solution to this error, I was also having this issue but when trying to log a user in. It turned out to be I had forgotten to await .signInWithPassword() so it was trying to set the cookie after the response had been sent. Oops
Hi @david-plugge - thanks for your help again with this, just wanted to raise this as I realized there are still issues with the current approach of omitting credentials. For example, if I’m protecting my API routes following the guide here or here:
And I have this in my hooks.server.ts
The
sessionin that case is always null, and therefore will not be able to hit the endpoint since it’ll throw a 401.Do you think there would be any workarounds in the meantime?
And to clarify regarding a longer-term plan, would this actually be an issue the auth-helpers maintainers would be figuring out a patch for or is this something that will require the SvelteKit team to address?