FAILED_TO_GET_SESSION in user signout (latest version)

Hi there, I am using: "better-auth": "^1.3.24", "next": "15.2.4", "@daveyplate/better-auth-ui": "^3.2.5", Everything works fine when during signin and during the user session, but when the user signs out (even manually, just after signing in), the following error arises:
.ts
AUTH ERROR {
"response": {},
"responseText": "{\"code\":\"FAILED_TO_GET_SESSION\",\"message\":\"Failed to get session\"}",
"request": {
"baseURL": "http://localhost:3000/api/auth",
"credentials": "include",
"method": "POST",
"plugins": [
{
"id": "lifecycle-hooks",
"name": "lifecycle-hooks",
"hooks": {}
},
{
"id": "redirect",
"name": "Redirect",
"hooks": {}
},
{
"id": "apply-schema",
"name": "Apply Schema",
"version": "1.0.0"
}
],
"body": "{}",
"url": "http://localhost:3000/api/auth/sign-out",
"headers": {},
"signal": {}
},
"error": {
"code": "FAILED_TO_GET_SESSION",
"message": "Failed to get session",
"status": 400,
"statusText": "BAD_REQUEST"
}
} at [authClient]
.ts
AUTH ERROR {
"response": {},
"responseText": "{\"code\":\"FAILED_TO_GET_SESSION\",\"message\":\"Failed to get session\"}",
"request": {
"baseURL": "http://localhost:3000/api/auth",
"credentials": "include",
"method": "POST",
"plugins": [
{
"id": "lifecycle-hooks",
"name": "lifecycle-hooks",
"hooks": {}
},
{
"id": "redirect",
"name": "Redirect",
"hooks": {}
},
{
"id": "apply-schema",
"name": "Apply Schema",
"version": "1.0.0"
}
],
"body": "{}",
"url": "http://localhost:3000/api/auth/sign-out",
"headers": {},
"signal": {}
},
"error": {
"code": "FAILED_TO_GET_SESSION",
"message": "Failed to get session",
"status": 400,
"statusText": "BAD_REQUEST"
}
} at [authClient]
` I have read the posts related to this error, and the suggestion is to upgrade packages, but I am already in the latest version. Could you, please, point me to the right direction to debug this? Thank you!
13 Replies
Risatoga
RisatogaOP2d ago
My config:
//provider.tsx

<BetterAuthUIProvider
authClient={authClient}
// @ts-expect-error "idk"
navigate={router.push}
// @ts-expect-error "idk"
replace={router.replace}
settings={{
url: '/app/settings',
}}
onSessionChange={() => {
router.refresh();
}}
// @ts-expect-error "idk"
Link={Link}
settingsUrl='/app/settings'
additionalFields={{}}
redirectTo='/app'
localization={{
// lots of stuff here!
}}
>
{children}
</BetterAuthUIProvider>
//provider.tsx

<BetterAuthUIProvider
authClient={authClient}
// @ts-expect-error "idk"
navigate={router.push}
// @ts-expect-error "idk"
replace={router.replace}
settings={{
url: '/app/settings',
}}
onSessionChange={() => {
router.refresh();
}}
// @ts-expect-error "idk"
Link={Link}
settingsUrl='/app/settings'
additionalFields={{}}
redirectTo='/app'
localization={{
// lots of stuff here!
}}
>
{children}
</BetterAuthUIProvider>
// client.ts
export const authClient = createAuthClient({
plugins: [],
baseURL: process.env.NEXT_PUBLIC_APP_URL!,
fetchOptions: {
onError: (ctx) => {
// Log the full context to see the structure
logger.error('🟩 AUTH ERROR', ctx);

// Create an Error object for PostHog

const error = new Error(ctx.error.message || 'Authentication error');
error.name = 'AuthError';

// Use captureException for proper error tracking
posthog.captureException(error, {
tags: {
code: ctx.error.code,
status: ctx.error.status,
source: 'better-auth-client',
},
extra: {
response: ctx.response,
error: ctx.error,
},
});

// Also capture as a custom event for additional tracking
posthog.capture('auth_error', {
message: ctx.error.message,
code: ctx.error.code,
status: ctx.error.status,
$exception: true,
});
},
},
});
// client.ts
export const authClient = createAuthClient({
plugins: [],
baseURL: process.env.NEXT_PUBLIC_APP_URL!,
fetchOptions: {
onError: (ctx) => {
// Log the full context to see the structure
logger.error('🟩 AUTH ERROR', ctx);

// Create an Error object for PostHog

const error = new Error(ctx.error.message || 'Authentication error');
error.name = 'AuthError';

// Use captureException for proper error tracking
posthog.captureException(error, {
tags: {
code: ctx.error.code,
status: ctx.error.status,
source: 'better-auth-client',
},
extra: {
response: ctx.response,
error: ctx.error,
},
});

// Also capture as a custom event for additional tracking
posthog.capture('auth_error', {
message: ctx.error.message,
code: ctx.error.code,
status: ctx.error.status,
$exception: true,
});
},
},
});
// server.ts (Simplified for brevity but still throws the same error)
export const auth = betterAuth({
trustedOrigins: [process.env.NEXT_PUBLIC_APP_URL!],
baseURL: process.env.NEXT_PUBLIC_APP_URL!,
user: {
modelName: 'User',
},
socialProviders: {
linkedin: {
clientId: process.env.LINKEDIN_CLIENT_ID!,
clientSecret: process.env.LINKEDIN_CLIENT_SECRET!,
},
},
emailAndPassword: {
enabled: true,
},
advanced: {
database: {
generateId: false,
},
},
database: prismaAdapter(db, {
provider: 'postgresql',
}),
plugins: [nextCookies()],
});
// server.ts (Simplified for brevity but still throws the same error)
export const auth = betterAuth({
trustedOrigins: [process.env.NEXT_PUBLIC_APP_URL!],
baseURL: process.env.NEXT_PUBLIC_APP_URL!,
user: {
modelName: 'User',
},
socialProviders: {
linkedin: {
clientId: process.env.LINKEDIN_CLIENT_ID!,
clientSecret: process.env.LINKEDIN_CLIENT_SECRET!,
},
},
emailAndPassword: {
enabled: true,
},
advanced: {
database: {
generateId: false,
},
},
database: prismaAdapter(db, {
provider: 'postgresql',
}),
plugins: [nextCookies()],
});
Thank you! 🙏🏻
Risatoga
RisatogaOP2d ago
In case it helps, when the I signout (that is when the error happens), these are the request that I can see in my network tab:
No description
Risatoga
RisatogaOP2d ago
the UI shows (it changes between this error and the above mentioned one):
Risatoga
RisatogaOP2d ago
No description
Risatoga
RisatogaOP2d ago
the first request (a react server component payload...??) looks like this:
No description
Risatoga
RisatogaOP2d ago
then...
Risatoga
RisatogaOP2d ago
No description
Risatoga
RisatogaOP2d ago
No description
Risatoga
RisatogaOP2d ago
No description
Risatoga
RisatogaOP2d ago
No description
Risatoga
RisatogaOP2d ago
Even if I do this:
<Button
onClick={async () => {
await authClient.signOut({});
await wait(5000);
router.push('/');
}}
>
Sign Out
</Button>
<Button
onClick={async () => {
await authClient.signOut({});
await wait(5000);
router.push('/');
}}
>
Sign Out
</Button>
` (waiting 5 seconds) I get the same error:
Risatoga
RisatogaOP2d ago
No description
Risatoga
RisatogaOP2d ago
fixed ! tomorrow afternoon I will write a brief explanation, but it was related to a third part widget using a shadowRoot There it goes: - In my app, I am using a chat widget comming from a third party saas. - That chat widget, requires: 1. to add a "div" to my app, where I am expected to set the style of the widget, via css custom properties 2. To run a script to load the widget - But (and here comes the catch) that script also "imperatively" changed that dive for a custom html element - Because this last step was done "outside react", react was not aware that the div that I added was no longer there. - When the component unmounts (on user log out, since the chat was in the auth layout only), React tries to unmount that - now non existent - div - It cannot find it, which causes the "removeChild" error. - That somehow ended up affecting and triggering other errors, which were not the root cause. Fix: 1. Either keep the chat component and never unmount it (for ex, putting it in the app layout), though this is not what I wanted 2. ...or adding the div also "outside of the react flow", imperatively in a useEffect. I did #2 and it's working fine again 🙂

Did you find this page helpful?