Server Actions and Cookies sending error: Cannot set headers after they are sent to the clien
Maybe I am misunderstanding something here. I am following the docs for Actions. Basically, what this component is supposed to do is check for the pressence of a session cookie. And, if the user is authenticated, redirects the client to the dashboard page. And if not, it redirects the client to the login page.
I included the action definition in the comments.
17 Replies
Here is the definition of the action.
So, can I not call a server action from the component manually instead of from a form submission?
Here's the definition of the
getUserSession()
function.
I just took it from the SolidStart vDocs.
To summarize, the problem I am getting is when this component (the home page) is loaded, the app crashes saying that I am trying to set the session after the cookie has been sent to the client.
Thanks for the help.Grasping at straws here, but:
The underlying library function from h3
useSession()
takes the h3 event in the first parameter position.
vinxi creates a wrapper around that which goes on some extensive detour into async context to obtain that event (which contains the request) if it isn't supplied.
So I would try
and see if that changes things.
(For all I know that does exactly the same thing.)Handle Session - h3
Remember your users using a session.
Seems to do the same thing. Still getting the same error.
I’m wondering… maybe it’s because I can’t run a server-only action outside a form submission? The docs don’t say anything about that though… so, no idea.
My first attempt was just doing the check with a data loader function. However, the data loader only executes during the first load. I need this check to run every time the user goes to the route though, which is why I opted for an action.
Maybe I need to take a different approach?
The error is suggesting that something is trying to modify headers after the response body has already started flushing. Typically that happens when a await is missing somewhere.
Hmm. Let me check.
I assume that getAuthenticatedUserForToken or refreshAuthTokens don't do anything header or cookie related?
Nope. They just make a
fetch()
call and return the respective data (the authenticated user and the auth tokens respectively). Updating the session is happening in the call to user session.update() in the action function itself.
The only un-await-ed promise I’m seeing is the call to loadAuthenticatedUser()
action in the main component.
However, that’s the same thing that the example in the actions section in the docs is doing…SolidStart Release Candidate Documentation
SolidStart Release Candidate Documentation
Early release documentation and resources for SolidStart Release Candidate
Have you tried to implement a simple action and got it to work? I doubt it's a form vs. no form issue.
I'd be tempted to start with the simplest possible "fake" version just to get it to work end to end and then build it out from there to see what makes it break.
Just by reviewing the code it's difficult to judge what may be accessing the request at an inappropriate time.
I just did. I created this basic action that just clears the session and then returns. It is still throwing the same error.
Here's the updated component. I basically just commented out the original useAction() and replaced it with the dummy.
Let me test it if it with an action that just returns immediately. If this works, my best guess is the error is somehow in how I set up the getUserSession() function?
Okay. So it looks like the error is only being thrown whenever the session is being updated. So, my guess is the session is what is causing the error…
In combination with the error message the suggestion is that by the time
session.update
is reached the response headers have already been sent—which is counterintuitive given that we haven't reached a return statement of any sort.
However if the response started streaming this is the type of error that could occur.
This isn't happening during SSR by any chance?
https://github.com/nksaraf/vinxi/issues/208GitHub
Error: Cannot set headers after they are sent to the client · Issue...
It seems it's not possible to set the session at present in my solid-start project. All request are returning: Error: Cannot set headers after they are sent to the client at ServerResponse.setH...
Yes. This is using SSR. I scattered some logs around the action. And it seems the error occurs during the
getUserSession()
call, which indicates I am experiencing the same issue as you linked.
So, I guess the solution to this error would be to do the checks from within a middleware instead of an action.
Let me try that out really quick.
It’s still not updated in the docs… at least from what I see. So, hopefully that changes soon.Tremors
YouTube
Free Range Graboid | Tremors 5: Bloodlines
The tentacles detach?! Why is it that critical need to know information always seems to escape Burt Gummer?
Stream Tremors Now on Peacock: https://www.peacocktv.com/?cid=20200715librarytitlesymyt506&utm_campaign=20200715librarytitle&utm_source=yt&utm_medium=sym_yt_brandawareness_descriptionlink&utm_term=tremors
From Tremors 5: Bloodlines - Sur...
I guess I dodged a bullet then
GitHub
solid-start-sse-chat/src/middleware.ts at 5ade3b77d9cca0bbdc3459cc4...
Basic Chat demonstration with server-sent events (SSE) - peerreynders/solid-start-sse-chat
This helps a lot. Thanks.
Here I thought SolidStart “just works”. Lmao.
The cost of bleeding edge
Anyways. Thanks for the help my friend. Really appreciate it.
Just in case someone else is reading this with the same issue. It seems this issue only arises in actions involving SSR.
For server actions invoked via form action, this solution is not necessary.
At least as far as I can tell. My authentication form action seems to work just fine
Quick tip on this: the h3/vinxi session utilities always create a session cookie if it doesnt exist, which is suboptimal during streaming ssr render, because the response might already be sent. You can avoid this by first checking if the session cookie exists in the request, and only if does exist you run getSession/useSession.