Skip to content

fix(adapter-prisma): update error handling to Prisma's recommended approach #12862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Lqm1
Copy link
Contributor

@Lqm1 Lqm1 commented Apr 9, 2025

☕️ Reasoning

In our Cloudflare Workers + Next.js + OpenNext + Next-Auth + Prisma web application, we encountered errors related to CommonJS and ESM compatibility. Upon investigation, it was discovered that in a CommonJS environment, the module "@prisma/client/runtime/library" was being interpreted and invoked as "@prisma/client/runtime/library.mjs", which caused the error. While explicitly importing "@prisma/client/runtime/library.js" could serve as a workaround, the recommended approach is to avoid importing the runtime library directly. Instead, we should import "Prisma" from "@prisma/client" (using import { Prisma } from "@prisma/client") and reference Prisma.PrismaClientKnownRequestError for error handling, as suggested by Prisma's troubleshooting and error handling guidelines.

For more details, please refer to the Prisma documentation on handling exceptions and errors:
https://www.prisma.io/docs/orm/prisma-client/debugging-and-troubleshooting/handling-exceptions-and-errors

🧢 Checklist

  • Documentation
  • Tests
  • Ready to be merged

🎫 Affected issues

📌 Resources

@Lqm1 Lqm1 requested a review from ndom91 as a code owner April 9, 2025 14:06
Copy link

vercel bot commented Apr 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
auth-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 9, 2025 2:10pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
next-auth-docs ⬜️ Ignored (Inspect) Visit Preview Apr 9, 2025 2:10pm

Copy link

vercel bot commented Apr 9, 2025

@Lqm1 is attempting to deploy a commit to the authjs Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions bot added adapters Changes related to the core code concerning database adapters prisma @auth/prisma-adapter labels Apr 9, 2025
@Lqm1
Copy link
Contributor Author

Lqm1 commented Apr 9, 2025

Although tests have not been run yet, the patch applied using "patch-package" is working correctly in my web application.

@auth+prisma-adapter+2.8.0.patch
diff --git a/node_modules/@auth/prisma-adapter/index.js b/node_modules/@auth/prisma-adapter/index.js
index f914a8c..03b4fc0 100644
--- a/node_modules/@auth/prisma-adapter/index.js
+++ b/node_modules/@auth/prisma-adapter/index.js
@@ -1,98 +1,102 @@
-import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
+import { Prisma } from "@prisma/client";
 export function PrismaAdapter(prisma) {
-    const p = prisma;
-    return {
-        // We need to let Prisma generate the ID because our default UUID is incompatible with MongoDB
-        createUser: ({ id, ...data }) => p.user.create(stripUndefined(data)),
-        getUser: (id) => p.user.findUnique({ where: { id } }),
-        getUserByEmail: (email) => p.user.findUnique({ where: { email } }),
-        async getUserByAccount(provider_providerAccountId) {
-            const account = await p.account.findUnique({
-                where: { provider_providerAccountId },
-                include: { user: true },
-            });
-            return account?.user ?? null;
-        },
-        updateUser: ({ id, ...data }) => p.user.update({
-            where: { id },
-            ...stripUndefined(data),
-        }),
-        deleteUser: (id) => p.user.delete({ where: { id } }),
-        linkAccount: (data) => p.account.create({ data }),
-        unlinkAccount: (provider_providerAccountId) => p.account.delete({
-            where: { provider_providerAccountId },
-        }),
-        async getSessionAndUser(sessionToken) {
-            const userAndSession = await p.session.findUnique({
-                where: { sessionToken },
-                include: { user: true },
-            });
-            if (!userAndSession)
-                return null;
-            const { user, ...session } = userAndSession;
-            return { user, session };
-        },
-        createSession: (data) => p.session.create(stripUndefined(data)),
-        updateSession: (data) => p.session.update({
-            where: { sessionToken: data.sessionToken },
-            ...stripUndefined(data),
-        }),
-        deleteSession: (sessionToken) => p.session.delete({ where: { sessionToken } }),
-        async createVerificationToken(data) {
-            const verificationToken = await p.verificationToken.create(stripUndefined(data));
-            if ("id" in verificationToken && verificationToken.id)
-                delete verificationToken.id;
-            return verificationToken;
-        },
-        async useVerificationToken(identifier_token) {
-            try {
-                const verificationToken = await p.verificationToken.delete({
-                    where: { identifier_token },
-                });
-                if ("id" in verificationToken && verificationToken.id)
-                    delete verificationToken.id;
-                return verificationToken;
-            }
-            catch (error) {
-                // If token already used/deleted, just return null
-                // https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
-                if (error instanceof PrismaClientKnownRequestError &&
-                    error.code === "P2025")
-                    return null;
-                throw error;
-            }
-        },
-        async getAccount(providerAccountId, provider) {
-            return p.account.findFirst({
-                where: { providerAccountId, provider },
-            });
-        },
-        async createAuthenticator(data) {
-            return p.authenticator.create(stripUndefined(data));
-        },
-        async getAuthenticator(credentialID) {
-            return p.authenticator.findUnique({
-                where: { credentialID },
-            });
-        },
-        async listAuthenticatorsByUserId(userId) {
-            return p.authenticator.findMany({
-                where: { userId },
-            });
-        },
-        async updateAuthenticatorCounter(credentialID, counter) {
-            return p.authenticator.update({
-                where: { credentialID },
-                data: { counter },
-            });
-        },
-    };
+	const p = prisma;
+	return {
+		// We need to let Prisma generate the ID because our default UUID is incompatible with MongoDB
+		createUser: ({ id, ...data }) => p.user.create(stripUndefined(data)),
+		getUser: (id) => p.user.findUnique({ where: { id } }),
+		getUserByEmail: (email) => p.user.findUnique({ where: { email } }),
+		async getUserByAccount(provider_providerAccountId) {
+			const account = await p.account.findUnique({
+				where: { provider_providerAccountId },
+				include: { user: true },
+			});
+			return account?.user ?? null;
+		},
+		updateUser: ({ id, ...data }) =>
+			p.user.update({
+				where: { id },
+				...stripUndefined(data),
+			}),
+		deleteUser: (id) => p.user.delete({ where: { id } }),
+		linkAccount: (data) => p.account.create({ data }),
+		unlinkAccount: (provider_providerAccountId) =>
+			p.account.delete({
+				where: { provider_providerAccountId },
+			}),
+		async getSessionAndUser(sessionToken) {
+			const userAndSession = await p.session.findUnique({
+				where: { sessionToken },
+				include: { user: true },
+			});
+			if (!userAndSession) return null;
+			const { user, ...session } = userAndSession;
+			return { user, session };
+		},
+		createSession: (data) => p.session.create(stripUndefined(data)),
+		updateSession: (data) =>
+			p.session.update({
+				where: { sessionToken: data.sessionToken },
+				...stripUndefined(data),
+			}),
+		deleteSession: (sessionToken) =>
+			p.session.delete({ where: { sessionToken } }),
+		async createVerificationToken(data) {
+			const verificationToken = await p.verificationToken.create(
+				stripUndefined(data),
+			);
+			if ("id" in verificationToken && verificationToken.id)
+				delete verificationToken.id;
+			return verificationToken;
+		},
+		async useVerificationToken(identifier_token) {
+			try {
+				const verificationToken = await p.verificationToken.delete({
+					where: { identifier_token },
+				});
+				if ("id" in verificationToken && verificationToken.id)
+					delete verificationToken.id;
+				return verificationToken;
+			} catch (error) {
+				// If token already used/deleted, just return null
+				// https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
+				if (
+					error instanceof Prisma.PrismaClientKnownRequestError &&
+					error.code === "P2025"
+				)
+					return null;
+				throw error;
+			}
+		},
+		async getAccount(providerAccountId, provider) {
+			return p.account.findFirst({
+				where: { providerAccountId, provider },
+			});
+		},
+		async createAuthenticator(data) {
+			return p.authenticator.create(stripUndefined(data));
+		},
+		async getAuthenticator(credentialID) {
+			return p.authenticator.findUnique({
+				where: { credentialID },
+			});
+		},
+		async listAuthenticatorsByUserId(userId) {
+			return p.authenticator.findMany({
+				where: { userId },
+			});
+		},
+		async updateAuthenticatorCounter(credentialID, counter) {
+			return p.authenticator.update({
+				where: { credentialID },
+				data: { counter },
+			});
+		},
+	};
 }
 /** @see https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/null-and-undefined */
 function stripUndefined(obj) {
-    const data = {};
-    for (const key in obj)
-        if (obj[key] !== undefined)
-            data[key] = obj[key];
-    return { data };
+	const data = {};
+	for (const key in obj) if (obj[key] !== undefined) data[key] = obj[key];
+	return { data };
 }
diff --git a/node_modules/@auth/prisma-adapter/src/index.ts b/node_modules/@auth/prisma-adapter/src/index.ts
index 6daadab..ed1c80e 100644
--- a/node_modules/@auth/prisma-adapter/src/index.ts
+++ b/node_modules/@auth/prisma-adapter/src/index.ts
@@ -15,8 +15,7 @@
  *
  * @module @auth/prisma-adapter
  */
-import { type PrismaClient } from "@prisma/client"
-import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"
+import { type PrismaClient, Prisma } from "@prisma/client"
 import type {
   Adapter,
   AdapterAccount,
@@ -90,7 +89,7 @@ export function PrismaAdapter(
         // If token already used/deleted, just return null
         // https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
         if (
-          error instanceof PrismaClientKnownRequestError &&
+          error instanceof Prisma.PrismaClientKnownRequestError &&
           error.code === "P2025"
         )
           return null

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
adapters Changes related to the core code concerning database adapters prisma @auth/prisma-adapter
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant