'Invariant: cookies() expects to have requestAsyncStorage, none available.' websockets
Answered
stiltkl posted this in #help-forum
stiltklOP
I'm using next js 14 app router, and am initialising a websocket server for use within my app. I am attempting to access cookies when a websocket connection is made, I am doing so using the 'cookies()' function from 'next/headers' . When I attempt to call this function the server errors and drops the socket connection, in the chrome devtools logs I can see the attached error. It should be noted if I remove this call to cookies() the connection seems to be stable and everything works as intended. I have tested a few other server only functions, such as header() and redirect() aswell, these also cause similar errors that suggest that somehow this code is being ran in the client / not on the server?
If anybody could provide any pointers as to what might be causing this issue, I'd be greatly appreciative. I've been stuck with this issue for near a week now and it is really hindering my development. Thanks in advance.
If anybody could provide any pointers as to what might be causing this issue, I'd be greatly appreciative. I've been stuck with this issue for near a week now and it is really hindering my development. Thanks in advance.
Answered by Toyger
they still will work inside your server/client components, because they are within nextjs context, but not inside
server.ts you don't have nextjs context here so you need to work with it as with bare nodejs server.26 Replies
Toyger
it's not running on a client, it running inside custom server from node:http, not vercel nextjs built-in server.
you imported it at top
so you need to read cookies as from simple nodejs server
you imported it at top
import { createServer } from "node:http";so you need to read cookies as from simple nodejs server
wss.on('connection', (socket, req)=> {
const cookies = parseCookies(req.headers.cookie);
console.log(cookies);
})
function parseCookies(cookieHeader) {
const cookies = {};
if (cookieHeader) {
cookieHeader.split(';').forEach(cookie => {
const parts = cookie.split('=');
const key = parts[0].trim();
const value = parts[1].trim();
cookies[key] = value;
});
}
return cookies;
}stiltklOP
Ok so 'server side functions' can only run inside the built-in next server?
Thank you very much for the reply also!
@stiltkl Ok so 'server side functions' can only run inside the built-in next server?
Toyger
they still will work inside your server/client components, because they are within nextjs context, but not inside
server.ts you don't have nextjs context here so you need to work with it as with bare nodejs server.Answer
stiltklOP
Ok that acctually makes a lot of sense now that I think of it. Thanks for pointing it out. Would you be able to reccomend any way to perhaps integrate some websocket server that I could access into the next js context. Because I do ideally want access to next js functions even while Im using the sockets.
Toyger
from client side it's not a problem at all, you can open connection in any useefect even inside any page, you probably can even set this useeffect inside layout.ts, but your handler of websocket is still in
server.ts, so whatever you want to do here should be done without access to nextjs context.stiltklOP
Thanks but what I mean is there any way to configure my next js app such that server.ts’s created server can have access to next js context ?
@stiltkl Thanks but what I mean is there any way to configure my next js app such that server.ts’s created server can have access to next js context ?
is it possible for you to pass the
request object to the function inside the server.ts file?is it possible for you to send extra data whenever there is a websocket event being fired?
the idea of cookies() is that cookies will be attacked to every fetch calls made in the client. Thats why its also available on the server.
Toyger
I don't think that you can use context of next here, if you need to share some data to websocket, you can use header/cookies
@ᴉuɐpɹɐɐ is it possible for you to pass the `request` object to the function inside the server.ts file?
stiltklOP
How do you mean? I dont quite get what you mean sorry
where is the websocket connection created? from Next.js server or from the user's client?
@Toyger I don't think that you can use context of next here, if you need to share some data to websocket, you can use header/cookies
stiltklOP
I've come up with a solution using headers but it isnt ideal as I would like to use the same functionality for creating context for my ws to use, as i use for http. If its not atall possible then its fine I can just use request.headers.cookies but if there is some way I could access next js context functions in my ws server, it would be more than ideal.
@ᴉuɐpɹɐɐ where is the websocket connection created? from Next.js server or from the user's client?
stiltklOP
the users client I believe. The ws server though is created only after app.prepare has been completed. To be entirely honest I am not entirely too sure what app.prepare does. I just copied examples from online for how they went about setting up ws sockets, althought adimittedlyt I think most of them are now outdated, and event those that were present were very scarce
thats fine but i dont know if
cookies are being sent for every websocket events. and if they do you could always check themthe cookies() function needs the
request context object that is set in the Next.js server function calls such as route.js/page.js/server actions. I dont think it can be made outside of that.@Toyger it's not running on a client, it running inside custom server from node:http, not vercel nextjs built-in server.
you imported it at top
js
import { createServer } from "node:http";
so you need to read cookies as from simple nodejs server
js
wss.on('connection', (socket, req)=> {
const cookies = parseCookies(req.headers.cookie);
console.log(cookies);
})
function parseCookies(cookieHeader) {
const cookies = {};
if (cookieHeader) {
cookieHeader.split(';').forEach(cookie => {
const parts = cookie.split('=');
const key = parts[0].trim();
const value = parts[1].trim();
cookies[key] = value;
});
}
return cookies;
}
You could try learning about AsyncLocalStorage (node.js API) into creating your own request context from the
req object herestiltklOP
Ok thanks, I'll look into that.
@stiltkl Ok thanks, I'll look into that.
would you be willing to look more into creating your own request context? I could share a few tweets/post on how Next.js's cookies() are made (believe me, its not made out of flour)
leerob recently made a post about that
stiltklOP
I would definitely be open to atleast looking into it. But for now I think I will likely just opt to not use the next js context functions and instead just create a function for reading cookies for ws requests seperate from the one that handles http. It seems alot simpler for the scale of the project I am working on.
https://x.com/leeerob/status/1771976818121437387?s=20
yeah, i thought this might be insightful for you. Im sorry for oversharing haha
yeah, i thought this might be insightful for you. Im sorry for oversharing haha
id not over-engineer it too
@ᴉuɐpɹɐɐ https://x.com/leeerob/status/1771976818121437387?s=20
yeah, i thought this might be insightful for you. Im sorry for oversharing haha
stiltklOP
No, theres no such thing as over sharing when it comes to someone asking for help with this sort of stuff. I'd rather too much information regarding the issue than too little!
Thank you.