You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It's possible for unstable_getServerSession to return a string as the session in the scenario above, if these conditions are met:
A custom error page must not be set in [...nextauth].ts
assertConfig must return a ConfigError inside unstable_getServerSession aka an error is thrown
It's due to this check here right at the end before final return.
NextAuthHandler verifies everything is set up correctly with assertConfig under the hood. If assertConfig returns a ConfigError, then NextAuthHandler returns an object shaped differently depending if you've created a custom error page yourself or not.
If you've got a custom error page, that object is shaped like this:
If you don't have a custom error page created, then the return from NextAuthHandler is shaped like this with a body key that is a string of html forming the default error page:
So in this case body (meaning the string of error page html) is then returned as the session, and also asserted as the Session type, further concealing the issue.
In my case, I was confused because I was getting a NO_SECRET error in prod (as expected), and I was expecting my server redirect in getServerSideProps to kick in because a valid session is not expected in this case. But since I had not created a custom error page, the session still came through as a string, skipping the redirect logic entirely and rendering my /dashboard, causing an error Application error: a client-side exception has occurred 😅
// pages/dashboard.tsexportconstgetServerSideProps: GetServerSideProps=async({ req, res })=>{constsession=awaitunstable_getServerSession(req,res,authOptions);console.log(typeofsession);console.log(session);if(!session){// would never get here in my case, since session exists as a string}};
Result in terminal:
// string// <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>:root{--border-width:1px;--border-radius:0.3rem;--color-error:#c94b4b;--color-info:#157efb;--color-info-text:#fff}.__next-auth-theme-auto,.__next-auth-theme-light{--color-background:#fff;--color-text:#000;--color-primary:#444;--color-control-border:#bbb;--color-button-active-background:#f9f9f9;--color-button-active-border:#aaa;--color-seperator:#ccc}.__next-auth-theme-dark{--color-background:#000;--color-text:#fff;--color-primary:#ccc;--color-control-border:#555;--color-button-active-background:#060606;--color-button-active-border:#666;--color-seperator:#444}@media (prefers-color-scheme:dark){.__next-auth-theme-auto{--color-background:#000;--color-text:#fff;--color-primary:#ccc;--color-control-border:#555;--color-button-active-background:#060606;--color-button-active-border:#666;--color-seperator:#444}}body{background-color:var(--color-background);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;margin:0;padding:0}h1{font-weight:400;margin-bottom:1.5rem;padding:0 1rem}h1,p{color:var(--color-text)}form{margin:0;padding:0}label{font-weight:500;margin-bottom:.25rem;text-align:left}input[type],label{color:var(--color-text);display:block}input[type]{background:var(--color-background);border:var(--border-width) solid var(--color-control-border);border-radius:var(--border-radius);box-shadow:inset 0 .1rem .2rem rgba(0,0,0,.2);box-sizing:border-box;font-size:1rem;padding:.5rem 1rem;width:100%}input[type]:focus{box-shadow:none}p{font-size:1.1rem;line-height:2rem;margin:0 0 1.5rem;padding:0 1rem}a.button{line-height:1rem;text-decoration:none}a.button,a.button:link,a.button:visited,button{background-color:var(--color-background);color:var(--color-primary)}a.button,button{border:var(--border-width) solid var(--color-control-border);border-radius:var(--border-radius);box-shadow:0 .15rem .3rem rgba(0,0,0,.15),inset 0 .1rem .2rem var(--color-background),inset 0 -.1rem .1rem rgba(0,0,0,.05);font-size:1rem;font-weight:500;margin:0 0 .75rem;padding:.75rem 1rem;position:relative;transition:all .1s ease-in-out}a.button:hover,button:hover{cursor:pointer}a.button:active,button:active{background-color:var(--color-button-active-background);border-color:var(--color-button-active-border);box-shadow:0 .15rem .3rem rgba(0,0,0,.15),inset 0 .1rem .2rem var(--color-background),inset 0 -.1rem .1rem rgba(0,0,0,.1);cursor:pointer}a.site{color:var(--color-primary);font-size:1rem;line-height:2rem;text-decoration:none}a.site:hover{text-decoration:underline}.page{display:grid;height:100%;margin:0;padding:0;place-items:center;position:absolute;width:100%}.page>div{padding:.5rem;text-align:center}.error a.button{display:inline-block;margin-top:.5rem;padding-left:2rem;padding-right:2rem}.error .message{margin-bottom:1.5rem}.signin a.button,.signin button,.signin input[type=text]{display:block;margin-left:auto;margin-right:auto}.signin hr{border:0;border-top:1px solid var(--color-seperator);display:block;margin:1.5em auto 0;overflow:visible}.signin hr:before{background:var(--color-background);color:#888;content:"or";padding:0 .4rem;position:relative;top:-.6rem}.signin .error{background:#f5f5f5;background:var(--color-info);border-radius:.3rem;font-weight:500}.signin .error p{color:var(--color-info-text);font-size:.9rem;line-height:1.2rem;padding:.5rem 1rem;text-align:left}.signin form,.signin>div{display:block}.signin form input[type],.signin>div input[type]{margin-bottom:.5rem}.signin form button,.signin>div button{width:100%}.signin form,.signin>div{max-width:300px}.signout .message{margin-bottom:1.5rem}.logo{display:inline-block;margin-top:100px;max-height:150px;max-width:300px}.card{border:1px solid var(--color-control-border);border-radius:5px;margin:50px auto;max-width:-webkit-max-content;max-width:-moz-max-content;max-width:max-content;padding:20px 50px}.card .header{color:var(--color-primary)}.section-header{color:var(--brand-color,var(--color-text))}</style><title>Error</title></head><body class="__next-auth-theme-auto"><div class="page"><div class="error"><div class="card"><h1>Server error</h1><div class="message"><div><p>There is a problem with the server configuration.</p><p>Check the server logs for more information.</p></div></div></div></div></div></body></html>
How to reproduce
These conditions must be true to experience it:
A custom error page must not be set in [...nextauth].ts
assertConfig must return a ConfigError inside unstable_getServerSession aka an error is thrown
If there's a problem under the hood, I'd expect that unstable_getServerSession should return null regardless of whether you've created a custom error page or not.
This does mirror the behavior of getSession which always returns null if an error is caught in fetchData.
I can submit a PR if you agree with this expected behavior.
The text was updated successfully, but these errors were encountered:
melanieseltzer
added
the
triage
Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
label
Aug 16, 2022
Thank you for the detailed bug report!
I've tested your reproduction and can confirm. This shouldn't be expected. PR welcome 🙌 I'd be glad to take a look
While you're at it, please also add a test in getServerSession.test.ts
ThangHuuVu
added
bug
Something isn't working
core
Refers to `@auth/core`
and removed
triage
Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
labels
Aug 21, 2022
Environment
Reproduction URL
https://github.com/melanieseltzer/next-auth-unstable_getServerSession-bug-repro
Describe the issue
Background
I am not using a custom error page:
My dashboard page:
Bug
It's possible for
unstable_getServerSession
to return astring
as the session in the scenario above, if these conditions are met:[...nextauth].ts
assertConfig
must return aConfigError
insideunstable_getServerSession
aka an error is thrownIt's due to this check here right at the end before final return.
NextAuthHandler
verifies everything is set up correctly withassertConfig
under the hood. IfassertConfig
returns aConfigError
, thenNextAuthHandler
returns an object shaped differently depending if you've created a custom error page yourself or not.If you've got a custom error page, that object is shaped like this:
Which fails this check so
null
is returned.If you don't have a custom error page created, then the return from
NextAuthHandler
is shaped like this with abody
key that is a string of html forming the default error page:This satisfies the if condition checking the existence of
body
.So in this case
body
(meaning the string of error page html) is then returned as the session, and also asserted as theSession
type, further concealing the issue.In my case, I was confused because I was getting a
NO_SECRET
error in prod (as expected), and I was expecting my server redirect ingetServerSideProps
to kick in because a validsession
is not expected in this case. But since I had not created a custom error page, thesession
still came through as a string, skipping the redirect logic entirely and rendering my/dashboard
, causing an errorApplication error: a client-side exception has occurred
😅Result in terminal:
How to reproduce
These conditions must be true to experience it:
[...nextauth].ts
assertConfig
must return aConfigError
insideunstable_getServerSession
aka an error is thrownPlease go to my example to repro this (with specific instructions): https://github.com/melanieseltzer/next-auth-unstable_getServerSession-bug-repro#readme
Expected behavior
If there's a problem under the hood, I'd expect that
unstable_getServerSession
should returnnull
regardless of whether you've created a custom error page or not.This does mirror the behavior of getSession which always returns
null
if an error is caught infetchData
.I can submit a PR if you agree with this expected behavior.
The text was updated successfully, but these errors were encountered: