getSession() called server side sometimes fails with the following error:
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error invalid json response body at [MY DOMAIN]/api/auth/session reason: Unexpected token < in JSON at position 0 {
error: {
message: 'invalid json response body at [MY DOMAIN]/api/auth/session reason: Unexpected token < in JSON at position 0',
stack: 'FetchError: invalid json response body at [MY DOMAIN]/api/auth/session reason: Unexpected token < in JSON at position 0\n' +
' at /var/task/node_modules/next/dist/compiled/node-fetch/index.js:1:49606\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)',
name: 'FetchError'
},
...
}
Errors are occurring in the production environment: the app is deployed on Vercel and connected to an Atlas M0 MongoDB cluster (it's the free shared cluster of MongoDB Atlas).
The app works 90% of the time and the errors occur very randomly. I use react-query (with Query Retries enabled) to make requests to API endpoints which uses getSession for authentication and usually, after the first retry, the failed request doesn't fail anymore. With the retry option enabled, users do not experience any problem apart from slower loading because of duplicated requests.
My debug considerations
M0 shared cluster isn't very suitable for production environments (but the application has low traffic and E2E tests don't fail when auth is not required)
AWS Lambda functions (working behind Vercel) are slow to wake up from idle (lifecycle docs)
The application has low traffic, but I have multiple E2E tests running every 5 minutes that should also avoid cold starts I believe, but I'm not very sure about how this works. I also have general uptime checks running every 3 minutes.
How to reproduce
Intermittent and difficult to reproduce. I test my API routes every 5 minutes and i got 8 errors in the last 24 hours. The next-auth setup is very simple:
[...nextauth].ts
import NextAuth from 'next-auth';
import EmailProvider from 'next-auth/providers/email';
import { MongoDBAdapter } from '@next-auth/mongodb-adapter';
import clientPromise from 'services/mongodb';
import sendEmail from 'services/sendEmail';
const uri = process.env.MONGODB_CONNECTION_STRING;
let client;
let clientPromise: Promise;
if (!uri) {
throw new Error('process.env.MONGODB_CONNECTION_STRING is falsy');
}
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!(global as any)._mongoClientPromise) {
client = new MongoClient(uri);
(global as any)._mongoClientPromise = client.connect();
}
clientPromise = (global as any)._mongoClientPromise;
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri);
clientPromise = client.connect();
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;
Environment
Reproduction URL
/api/auth/session
Describe the issue
getSession()
called server side sometimes fails with the following error:Errors are occurring in the production environment: the app is deployed on Vercel and connected to an Atlas M0 MongoDB cluster (it's the free shared cluster of MongoDB Atlas).
The app works 90% of the time and the errors occur very randomly. I use
react-query
(with Query Retries enabled) to make requests to API endpoints which usesgetSession
for authentication and usually, after the first retry, the failed request doesn't fail anymore. With theretry
option enabled, users do not experience any problem apart from slower loading because of duplicated requests.My debug considerations
The application has low traffic, but I have multiple E2E tests running every 5 minutes that should also avoid cold starts I believe, but I'm not very sure about how this works. I also have general uptime checks running every 3 minutes.
How to reproduce
Intermittent and difficult to reproduce. I test my API routes every 5 minutes and i got 8 errors in the last 24 hours. The next-auth setup is very simple:
const nextAuthUrl = process.env.NEXTAUTH_URL ?? '';
const getMagicLink = ({ token: _token, email: _email }: { token: string; email: string }) => { [...] };
export default NextAuth({ secret: process.env.NEXTAUTH_SECRET, adapter: MongoDBAdapter(clientPromise), providers: [ EmailProvider({ maxAge: 24 60 60, // 24h sendVerificationRequest: async ({ identifier: email, token }) => { await sendEmail({ to: email, templateName: 'next-auth-magic-link', vars: [ { name: 'MAGICLINK', content: getMagicLink({ email, token }), }, ], }); }, }), ], pages: { signIn: '/login', error: '/login', }, });
import { MongoClient } from 'mongodb';
const uri = process.env.MONGODB_CONNECTION_STRING;
let client; let clientPromise: Promise;
if (!uri) { throw new Error('process.env.MONGODB_CONNECTION_STRING is falsy'); }
if (process.env.NODE_ENV === 'development') { // In development mode, use a global variable so that the value // is preserved across module reloads caused by HMR (Hot Module Replacement). if (!(global as any)._mongoClientPromise) { client = new MongoClient(uri); (global as any)._mongoClientPromise = client.connect(); } clientPromise = (global as any)._mongoClientPromise; } else { // In production mode, it's best to not use a global variable. client = new MongoClient(uri); clientPromise = client.connect(); }
// Export a module-scoped MongoClient promise. By doing this in a // separate module, the client can be shared across functions. export default clientPromise;