Email OTP issues since 1.4.0 #2407

Open
opened 2026-03-13 09:50:59 -05:00 by GiteaMirror · 18 comments
Owner

Originally created by @elecrenPLB on GitHub (Nov 27, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Instantiate your prisma client (v7) with adapter PrismaMssql
  2. Configure your better-auth project with prisma adapter
  3. Configure the emailOtp plugin
  4. Try sending a verification otp using authClient.emailOtp.sendVerificationOtp

Current vs. Expected behavior

Current : The verification record is not created in my database (or is deleted instantly) and the sendVerificationOTP is never triggered.

Expected : The sendVerificationOTP is triggered and the verification record is created and visible in the database

What version of Better Auth are you using?

1.4.0 and above

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP Tue Nov 5 00:21:55 UTC 2024",
    "release": "5.15.167.4-microsoft-standard-WSL2",
    "cpuCount": 12,
    "cpuModel": "Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz",
    "totalMemory": "31.26 GB",
    "freeMemory": "22.05 GB"
  },
  "node": {
    "version": "v22.20.0",
    "env": "development"
  },
  "packageManager": {
    "name": "pnpm",
    "version": "10.17.1"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "16.0.1"
    },
    {
      "name": "react",
      "version": "19.2.0"
    }
  ],
  "databases": [
    {
      "name": "@prisma/client",
      "version": "^7.0.1"
    }
  ],
  "betterAuth": {
    "version": "^1.3.32",
    "config": {
      "trustedOrigins": [
        "http://localhost:3000"
      ],
      "databaseHooks": {
        "session": {
          "create": {}
        },
        "verification": {
          "create": {}
        }
      },
      "user": {
        "modelName": "CustomerUser",
        "deleteUser": {
          "enabled": true
        }
      },
      "session": {
        "modelName": "CustomerSession",
        "additionalFields": {
          "activeAccountId": {
            "type": "string",
            "required": true,
            "description": "The ID of the selected Salesforce account"
          }
        }
      },
      "account": {
        "modelName": "CustomerAccount"
      },
      "verification": {
        "modelName": "CustomerVerification"
      },
      "emailAndPassword": {
        "enabled": true
      },
      "plugins": [
        {
          "name": "email-otp",
          "config": {
            "id": "email-otp",
            "endpoints": {},
            "hooks": {
              "after": [
                {}
              ]
            },
            "$ERROR_CODES": {
              "OTP_EXPIRED": "OTP expired",
              "INVALID_OTP": "Invalid OTP",
              "TOO_MANY_ATTEMPTS": "Too many attempts"
            },
            "rateLimit": [
              {
                "window": 60,
                "max": 3
              },
              {
                "window": 60,
                "max": 3
              },
              {
                "window": 60,
                "max": 3
              },
              {
                "window": 60,
                "max": 3
              }
            ]
          }
        }
      ]
    }
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

async function sendEmailOTP({ email, otp, type }: { email: string; otp: string; type: string }) {
  console.log('[Better Auth] sendVerificationOTP called', {
    email,
    otp,
    type,
    timestamp: new Date().toISOString()
  })
  
  try {
    if (type === 'email-verification') {
      console.log('[Better Auth] Processing email-verification OTP')
      const templatePath = path.join(
        process.cwd(),
        'emails',
        'email-validation-otp.hbs'
      )
      const templateContent = fs.readFileSync(templatePath, 'utf8')
      const template = Handlebars.compile(templateContent)

      const html = template({
        code: otp
      })

      console.log('[Better Auth] Sending email to', email)
      await sendMail({
        to: email,
        from: env.MAIL_SENDER,
        subject: 'Vérification de votre email',
        html: html
      })
      console.log('[Better Auth] Email sent successfully')
    } else {
      console.log('[Better Auth] OTP type is not email-verification:', type)
    }
  } catch (error) {
    console.error('[Better Auth] Error in sendVerificationOTP:', error)
    throw error
  }
}

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: 'sqlserver'
  }),
  trustedOrigins: env.TRUSTED_ORIGINS || [],
  databaseHooks: {
    session: {
      create: {
        before: async (session, context) => {
          const activeAccountId = context?.headers?.get('x-active-account-id')

          if (activeAccountId) {
            return {
              data: {
                ...session,
                activeAccountId: activeAccountId
              }
            }
          }

          return false
        }
      }
    },
    verification: {
      create: {
        before: async (verification) => {
          const verificationRecords = await prisma.customerVerification.findMany()
          console.log('verificationRecords', verificationRecords)
          console.log('[Better Auth] Verification create BEFORE hook:', {
            id: verification.id,
            identifier: verification.identifier,
            value: verification.value,
            expiresAt: verification.expiresAt,
            timestamp: new Date().toISOString()
          })
          // Ne pas bloquer la création
          return { data: verification }
        },
        after: async (verification) => {
          console.log('[Better Auth] Verification create AFTER hook:', {
            id: verification.id,
            identifier: verification.identifier,
            type: verification.identifier?.includes('email-verification') ? 'email-verification' : 'other',
            timestamp: new Date().toISOString()
          })
          
          try {
            const exists = await prisma.customerVerification.findUnique({
              where: { id: verification.id }
            })
            console.log('exists', exists)
            console.log('[Better Auth] Verification record exists in DB:', !!exists)
          } catch (error) {
            console.error('[Better Auth] Error checking verification in DB:', error)
          }
          
          if (verification.identifier?.includes('email-verification-otp-')) {
            const email = verification.identifier.replace('email-verification-otp-', '')
            const otp = verification.value.split(':')[0]
            
            console.log('[Better Auth] Manually calling sendVerificationOTP from hook')
            sendEmailOTP({
              email,
              otp,
              type: 'email-verification'
            }).catch((error) => {
              console.error('[Better Auth] Error in manual sendVerificationOTP call:', error)
            })
          }
        }
      }
    }
  },
  user: {
    modelName: 'CustomerUser',
    deleteUser: {
      enabled: true
    }
  },
  session: {
    modelName: 'CustomerSession',
    additionalFields: {
      activeAccountId: {
        type: 'string',
        required: true,
        description: 'The ID of the selected Salesforce account'
      }
    }
  },
  account: {
    modelName: 'CustomerAccount'
  },
  verification: {
    modelName: 'CustomerVerification'
  },
  emailAndPassword: {
    enabled: true
  },
  plugins: [
    emailOTP({
      async sendVerificationOTP({ email, otp, type }) {
        // but it is also called manually from the verification.create.after hook
        // due to an issue with Prisma V7
        console.log('sendVerificationOTP by Better Auth', email, otp, type) // NEVER REACHED
        return await sendEmailOTP({ email, otp, type })
      }
    })
  ]
})

Additional context

Debug output :

verificationRecords []
[Better Auth] Verification create BEFORE hook: {
  id: undefined,
  identifier: 'email-verification-otp-email@email.com',
  value: '203624:0',
  expiresAt: 2025-11-27T12:13:05.159Z,
  timestamp: '2025-11-27T12:08:05.170Z'
}
[Better Auth] Verification create AFTER hook: {
  id: '4UXFvg7scXM2UNdhvUGSGr8Y5tx8uOhJ',
  identifier: 'email-verification-otp-email@email.com',
  type: 'email-verification',
  timestamp: '2025-11-27T12:08:05.212Z'
}
exists {
  id: '4UXFvg7scXM2UNdhvUGSGr8Y5tx8uOhJ',
  identifier: 'email-verification-otp-email@email.com',
  value: '203624:0',
  expiresAt: 2025-11-27T12:13:05.159Z,
  createdAt: 2025-11-27T12:08:05.159Z,
  updatedAt: 2025-11-27T12:08:05.159Z
}
[Better Auth] Verification record exists in DB: true
[Better Auth] Manually calling sendVerificationOTP from hook
[Better Auth] sendVerificationOTP called {
  email: 'email@email.com',
  otp: '203624',
  type: 'email-verification',
  timestamp: '2025-11-27T12:08:05.224Z'
}
[Better Auth] Processing email-verification OTP
[Better Auth] Sending email to email@email.com
[Better Auth] Email sent successfully

It works perfectly with prisma 6.


The function :

  plugins: [
    emailOTP({
      async sendVerificationOTP({ email, otp, type }) {
        // but it is also called manually from the verification.create.after hook
        // due to an issue with Prisma V7
        console.log('sendVerificationOTP by Better Auth', email, otp, type) // NEVER REACHED
        return await sendEmailOTP({ email, otp, type })
      }
    })
  ]

is never called.

Originally created by @elecrenPLB on GitHub (Nov 27, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Instantiate your prisma client (v7) with adapter PrismaMssql 2. Configure your better-auth project with prisma adapter 3. Configure the emailOtp plugin 4. Try sending a verification otp using authClient.emailOtp.sendVerificationOtp ### Current vs. Expected behavior Current : The verification record is not created in my database (or is deleted instantly) and the sendVerificationOTP is never triggered. Expected : The sendVerificationOTP is triggered and the verification record is created and visible in the database ### What version of Better Auth are you using? 1.4.0 and above ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP Tue Nov 5 00:21:55 UTC 2024", "release": "5.15.167.4-microsoft-standard-WSL2", "cpuCount": 12, "cpuModel": "Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz", "totalMemory": "31.26 GB", "freeMemory": "22.05 GB" }, "node": { "version": "v22.20.0", "env": "development" }, "packageManager": { "name": "pnpm", "version": "10.17.1" }, "frameworks": [ { "name": "next", "version": "16.0.1" }, { "name": "react", "version": "19.2.0" } ], "databases": [ { "name": "@prisma/client", "version": "^7.0.1" } ], "betterAuth": { "version": "^1.3.32", "config": { "trustedOrigins": [ "http://localhost:3000" ], "databaseHooks": { "session": { "create": {} }, "verification": { "create": {} } }, "user": { "modelName": "CustomerUser", "deleteUser": { "enabled": true } }, "session": { "modelName": "CustomerSession", "additionalFields": { "activeAccountId": { "type": "string", "required": true, "description": "The ID of the selected Salesforce account" } } }, "account": { "modelName": "CustomerAccount" }, "verification": { "modelName": "CustomerVerification" }, "emailAndPassword": { "enabled": true }, "plugins": [ { "name": "email-otp", "config": { "id": "email-otp", "endpoints": {}, "hooks": { "after": [ {} ] }, "$ERROR_CODES": { "OTP_EXPIRED": "OTP expired", "INVALID_OTP": "Invalid OTP", "TOO_MANY_ATTEMPTS": "Too many attempts" }, "rateLimit": [ { "window": 60, "max": 3 }, { "window": 60, "max": 3 }, { "window": 60, "max": 3 }, { "window": 60, "max": 3 } ] } } ] } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript async function sendEmailOTP({ email, otp, type }: { email: string; otp: string; type: string }) { console.log('[Better Auth] sendVerificationOTP called', { email, otp, type, timestamp: new Date().toISOString() }) try { if (type === 'email-verification') { console.log('[Better Auth] Processing email-verification OTP') const templatePath = path.join( process.cwd(), 'emails', 'email-validation-otp.hbs' ) const templateContent = fs.readFileSync(templatePath, 'utf8') const template = Handlebars.compile(templateContent) const html = template({ code: otp }) console.log('[Better Auth] Sending email to', email) await sendMail({ to: email, from: env.MAIL_SENDER, subject: 'Vérification de votre email', html: html }) console.log('[Better Auth] Email sent successfully') } else { console.log('[Better Auth] OTP type is not email-verification:', type) } } catch (error) { console.error('[Better Auth] Error in sendVerificationOTP:', error) throw error } } export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: 'sqlserver' }), trustedOrigins: env.TRUSTED_ORIGINS || [], databaseHooks: { session: { create: { before: async (session, context) => { const activeAccountId = context?.headers?.get('x-active-account-id') if (activeAccountId) { return { data: { ...session, activeAccountId: activeAccountId } } } return false } } }, verification: { create: { before: async (verification) => { const verificationRecords = await prisma.customerVerification.findMany() console.log('verificationRecords', verificationRecords) console.log('[Better Auth] Verification create BEFORE hook:', { id: verification.id, identifier: verification.identifier, value: verification.value, expiresAt: verification.expiresAt, timestamp: new Date().toISOString() }) // Ne pas bloquer la création return { data: verification } }, after: async (verification) => { console.log('[Better Auth] Verification create AFTER hook:', { id: verification.id, identifier: verification.identifier, type: verification.identifier?.includes('email-verification') ? 'email-verification' : 'other', timestamp: new Date().toISOString() }) try { const exists = await prisma.customerVerification.findUnique({ where: { id: verification.id } }) console.log('exists', exists) console.log('[Better Auth] Verification record exists in DB:', !!exists) } catch (error) { console.error('[Better Auth] Error checking verification in DB:', error) } if (verification.identifier?.includes('email-verification-otp-')) { const email = verification.identifier.replace('email-verification-otp-', '') const otp = verification.value.split(':')[0] console.log('[Better Auth] Manually calling sendVerificationOTP from hook') sendEmailOTP({ email, otp, type: 'email-verification' }).catch((error) => { console.error('[Better Auth] Error in manual sendVerificationOTP call:', error) }) } } } } }, user: { modelName: 'CustomerUser', deleteUser: { enabled: true } }, session: { modelName: 'CustomerSession', additionalFields: { activeAccountId: { type: 'string', required: true, description: 'The ID of the selected Salesforce account' } } }, account: { modelName: 'CustomerAccount' }, verification: { modelName: 'CustomerVerification' }, emailAndPassword: { enabled: true }, plugins: [ emailOTP({ async sendVerificationOTP({ email, otp, type }) { // but it is also called manually from the verification.create.after hook // due to an issue with Prisma V7 console.log('sendVerificationOTP by Better Auth', email, otp, type) // NEVER REACHED return await sendEmailOTP({ email, otp, type }) } }) ] }) ``` ### Additional context Debug output : ``` verificationRecords [] [Better Auth] Verification create BEFORE hook: { id: undefined, identifier: 'email-verification-otp-email@email.com', value: '203624:0', expiresAt: 2025-11-27T12:13:05.159Z, timestamp: '2025-11-27T12:08:05.170Z' } [Better Auth] Verification create AFTER hook: { id: '4UXFvg7scXM2UNdhvUGSGr8Y5tx8uOhJ', identifier: 'email-verification-otp-email@email.com', type: 'email-verification', timestamp: '2025-11-27T12:08:05.212Z' } exists { id: '4UXFvg7scXM2UNdhvUGSGr8Y5tx8uOhJ', identifier: 'email-verification-otp-email@email.com', value: '203624:0', expiresAt: 2025-11-27T12:13:05.159Z, createdAt: 2025-11-27T12:08:05.159Z, updatedAt: 2025-11-27T12:08:05.159Z } [Better Auth] Verification record exists in DB: true [Better Auth] Manually calling sendVerificationOTP from hook [Better Auth] sendVerificationOTP called { email: 'email@email.com', otp: '203624', type: 'email-verification', timestamp: '2025-11-27T12:08:05.224Z' } [Better Auth] Processing email-verification OTP [Better Auth] Sending email to email@email.com [Better Auth] Email sent successfully ``` --- It works perfectly with prisma 6. --- The function : ``` plugins: [ emailOTP({ async sendVerificationOTP({ email, otp, type }) { // but it is also called manually from the verification.create.after hook // due to an issue with Prisma V7 console.log('sendVerificationOTP by Better Auth', email, otp, type) // NEVER REACHED return await sendEmailOTP({ email, otp, type }) } }) ] ``` is never called.
GiteaMirror added the bug label 2026-03-13 09:50:59 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Nov 27, 2025):

It looks like with Prisma v7 the sendVerificationOTP method defined in your emailOTP plugin isn’t being triggered, even though your verification.create.after hook is working properly and manually calling sendVerificationOTP as intended. This behavior suggests that the plugin’s injected call isn’t being executed—likely an issue with how the Prisma v7 adapter handles hook order or method invocation compared to Prisma v6. You might consider the following next steps:

• Verify you’re using the latest compatible version of our Prisma adapter for Prisma v7, as improvements or fixes may have been released.
• As a temporary workaround, continue to rely on your manual call from the verification.create.after hook to send your OTP emails.
• Double-check your adapter and plugin configuration to ensure no changes in Prisma v7 affect the lifecycle of your verification record or hook execution.
• If the issue persists, please open an issue or tag @bekacru and @ping__ so we can investigate further.

tag @better-auth-agent if you would like an answer from the Agent. Any additional details you can share about your setup will help us diagnose the issue further—do you have other integrations using Prisma v7 that might be affected?

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Nov 27, 2025): It looks like with Prisma v7 the sendVerificationOTP method defined in your emailOTP plugin isn’t being triggered, even though your verification.create.after hook is working properly and manually calling sendVerificationOTP as intended. This behavior suggests that the plugin’s injected call isn’t being executed—likely an issue with how the Prisma v7 adapter handles hook order or method invocation compared to Prisma v6. You might consider the following next steps: • Verify you’re using the latest compatible version of our Prisma adapter for Prisma v7, as improvements or fixes may have been released. • As a temporary workaround, continue to rely on your manual call from the verification.create.after hook to send your OTP emails. • Double-check your adapter and plugin configuration to ensure no changes in Prisma v7 affect the lifecycle of your verification record or hook execution. • If the issue persists, please open an issue or tag @bekacru and @ping__ so we can investigate further. tag @better-auth-agent if you would like an answer from the Agent. Any additional details you can share about your setup will help us diagnose the issue further—do you have other integrations using Prisma v7 that might be affected? <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@dosubot[bot] commented on GitHub (Nov 27, 2025):

Hi @elecrenPLB! I'm Dosu and I’m helping the better-auth team.

The sendVerificationOTP function in the emailOTP plugin is only triggered by the plugin's own endpoint logic—not by database hooks or direct verification record creation. The typical flow is: the /api/email-otp/send-verification-otp endpoint creates a verification record, then (if the user exists, or sign-in is allowed for new users) calls your sendVerificationOTP callback. If the verification record creation fails, is aborted by a hook, or the user doesn't exist, the function is never called and the record may be deleted immediately (plugin code reference).

With Prisma v7, there are known issues with schema mapping and config changes (like custom model names or CLI-generated schema mismatches) that can cause verification record creation to silently fail or abort, which prevents the plugin from firing its callback (schema mapping issue, Prisma v7 migration). This is why your manual after-hook workaround works: it bypasses the plugin's endpoint logic and sends the OTP directly after the record is created.

To troubleshoot and fix:

  • Make sure you're using the /api/email-otp/send-verification-otp endpoint (not just creating verification records directly).
  • Double-check that your Better Auth config model and field names (especially for verification) exactly match your Prisma schema. Prisma v7 requires manual updates to the schema and config after CLI generation.
  • Enable debug logging in your adapter to trace verification record creation and catch any silent errors.
  • If you use custom model names, verify that the adapter is mapping them correctly to your Prisma schema.

Until Better Auth fully supports Prisma v7 schema/config changes, your manual after-hook workaround is a valid solution. If you want to track this for future fixes, see the Prisma v7 compatibility issue.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 27, 2025): <!-- Greeting --> Hi @elecrenPLB! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> The `sendVerificationOTP` function in the emailOTP plugin is only triggered by the plugin's own endpoint logic—not by database hooks or direct verification record creation. The typical flow is: the `/api/email-otp/send-verification-otp` endpoint creates a verification record, then (if the user exists, or sign-in is allowed for new users) calls your `sendVerificationOTP` callback. If the verification record creation fails, is aborted by a hook, or the user doesn't exist, the function is never called and the record may be deleted immediately ([plugin code reference](https://github.com/better-auth/better-auth/blob/98803e1c5f4fe93d9e13ab5917ab8f688b132973/packages/better-auth/src/plugins/email-otp/index.ts#L223-L1223)). With Prisma v7, there are known issues with schema mapping and config changes (like custom model names or CLI-generated schema mismatches) that can cause verification record creation to silently fail or abort, which prevents the plugin from firing its callback ([schema mapping issue](https://github.com/better-auth/better-auth/issues/4781), [Prisma v7 migration](https://github.com/better-auth/better-auth/issues/6277)). This is why your manual after-hook workaround works: it bypasses the plugin's endpoint logic and sends the OTP directly after the record is created. To troubleshoot and fix: - Make sure you're using the `/api/email-otp/send-verification-otp` endpoint (not just creating verification records directly). - Double-check that your Better Auth config model and field names (especially for `verification`) exactly match your Prisma schema. Prisma v7 requires manual updates to the schema and config after CLI generation. - Enable debug logging in your adapter to trace verification record creation and catch any silent errors. - If you use custom model names, verify that the adapter is mapping them correctly to your Prisma schema. Until Better Auth fully supports Prisma v7 schema/config changes, your manual after-hook workaround is a valid solution. If you want to track this for future fixes, see the [Prisma v7 compatibility issue](https://github.com/better-auth/better-auth/issues/6277). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/3ea388c1-5cd9-4761-8b9b-7f094f5e53c0?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/3ea388c1-5cd9-4761-8b9b-7f094f5e53c0?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/3ea388c1-5cd9-4761-8b9b-7f094f5e53c0?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/3ea388c1-5cd9-4761-8b9b-7f094f5e53c0?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/3ea388c1-5cd9-4761-8b9b-7f094f5e53c0?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/3ea388c1-5cd9-4761-8b9b-7f094f5e53c0?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/3ea388c1-5cd9-4761-8b9b-7f094f5e53c0?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20%60sendVerificationOTP%60%20function%20in%20the%20emailOTP%20plugin%20is%20only%20triggered%20by%20the%20plugin%27s%20own%20endpoint%20logic%E2%80%94not%20by%20database%20hooks%20or%20direct%20verification%20record%20creation.%20The%20typical%20flow%20is%3A%20the%20%60/api/email-otp/send-verification-otp%60%20endpoint%20creates%20a%20verification%20record%2C%20then%20%28if%20the%20user%20exists%2C%20or%20sign-in%20is%20allowed%20for%20new%20users%29%20calls%20your%20%60sendVerificationOTP%60%20callback.%20If%20the%20verification%20record%20creation%20fails%2C%20is%20aborted%20by%20a%20hook%2C%20or%20the%20user%20doesn%27t%20exist%2C%20the%20function%20is%20never%20called%20and%20the%20record%20may%20be%20deleted%20immediately%C2%A0%28%5Bplugin%20code%20reference%5D%28https%3A//github.com/better-auth/better-auth/blob/98803e1c5f4fe93d9e13ab5917ab8f688b132973/packages/better-auth/src/plugins/email-otp/index.ts%23L223-L1223%29%29.%0A%0AWith%20Prisma%20v7%2C%20there%20are%20known%20issues%20with%20schema%20mapping%20and%20config%20changes%20%28like%20custom%20model%20names%20or%20CLI-generated%20schema%20mismatches%29%20that%20can%20cause%20verification%20record%20creation%20to%20silently%20fail%20or%20abort%2C%20which%20prevents%20the%20plugin%20from%20firing%20its%20callback%C2%A0%28%5Bschema%20mapping%20issue%5D%28https%3A//github.com/better-auth/better-auth/issues/4781%29%2C%20%5BPrisma%20v7%20migration%5D%28https%3A//github.com/better-auth/better-auth/issues/6277%29%29.%20This%20is%20why%20your%20manual%20after-hook%20workaround%20works%3A%20it%20bypasses%20the%20plugin%27s%20endpoint%20logic%20and%20sends%20the%20OTP%20directly%20after%20the%20record%20is%20created.%0A%0ATo%20troubleshoot%20and%20fix%3A%0A-%20Make%20sure%20you%27re%20using%20the%20%60/api/email-otp/send-verification-otp%60%20endpoint%20%28not%20just%20creating%20verification%20records%20directly%29.%0A-%20Double-check%20that%20your%20Better%20Auth%20config%20model%20and%20field%20names%20%28especially%20for%20%60verification%60%29%20exactly%20match%20your%20Prisma%20schema.%20Prisma%20v7%20requires%20manual%20updates%20to%20the%20schema%20and%20config%20after%20CLI%20generation.%0A-%20Enable%20debug%20logging%20in%20your%20adapter%20to%20trace%20verification%20record%20creation%20and%20catch%20any%20silent%20errors.%0A-%20If%20you%20use%20custom%20model%20names%2C%20verify%20that%20the%20adapter%20is%20mapping%20them%20correctly%20to%20your%20Prisma%20schema.%0A%0AUntil%20Better%20Auth%20fully%20supports%20Prisma%20v7%20schema/config%20changes%2C%20your%20manual%20after-hook%20workaround%20is%20a%20valid%20solution.%20If%20you%20want%20to%20track%20this%20for%20future%20fixes%2C%20see%20the%20%5BPrisma%20v7%20compatibility%20issue%5D%28https%3A//github.com/better-auth/better-auth/issues/6277%29.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6354)
Author
Owner

@elecrenPLB commented on GitHub (Nov 27, 2025):

The manual send is for debugging purpose only because the verification record does not persist in the database.
The email is sent with the code, but it is impossible to verify it because it is, apparently, deleted instantly.

SELECT * FROM CustomerVerification;

Shows me no results and the debug line :

verificationRecords []

is always empty.

@Bekacru

@elecrenPLB commented on GitHub (Nov 27, 2025): The manual send is for debugging purpose only because the verification record does not persist in the database. The email is sent with the code, but it is impossible to verify it because it is, apparently, deleted instantly. ``` SELECT * FROM CustomerVerification; ``` Shows me no results and the debug line : ``` verificationRecords [] ``` is always empty. @Bekacru
Author
Owner

@elecrenPLB commented on GitHub (Nov 27, 2025):

After further investigation, I'm not sure it is related to prisma version. It seems there is a bug with email-otp since 1.4.0

@elecrenPLB commented on GitHub (Nov 27, 2025): After further investigation, I'm not sure it is related to prisma version. It seems there is a bug with email-otp since 1.4.0
Author
Owner

@jslno commented on GitHub (Nov 28, 2025):

Looking into it 👀

@jslno commented on GitHub (Nov 28, 2025): Looking into it :eyes:
Author
Owner

@jslno commented on GitHub (Nov 28, 2025):

Are you getting any error thrown or logged in console?

@jslno commented on GitHub (Nov 28, 2025): Are you getting any error thrown or logged in console?
Author
Owner

@BradCameron2810 commented on GitHub (Nov 28, 2025):

Npn error

On Sat, 29 Nov 2025 at 00.08, Joél Solano @.***> wrote:

jslno left a comment (better-auth/better-auth#6354)
https://github.com/better-auth/better-auth/issues/6354#issuecomment-3589820218

Are you getting any error thrown or logged in console?


Reply to this email directly, view it on GitHub
https://github.com/better-auth/better-auth/issues/6354#issuecomment-3589820218,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/BUN5GTDN2X2TZYF2HZK6LSD37BXPJAVCNFSM6AAAAACNLU57IKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTKOBZHAZDAMRRHA
.
You are receiving this because you are subscribed to this thread.Message
ID: @.***>

@BradCameron2810 commented on GitHub (Nov 28, 2025): Npn error On Sat, 29 Nov 2025 at 00.08, Joél Solano ***@***.***> wrote: > *jslno* left a comment (better-auth/better-auth#6354) > <https://github.com/better-auth/better-auth/issues/6354#issuecomment-3589820218> > > Are you getting any error thrown or logged in console? > > — > Reply to this email directly, view it on GitHub > <https://github.com/better-auth/better-auth/issues/6354#issuecomment-3589820218>, > or unsubscribe > <https://github.com/notifications/unsubscribe-auth/BUN5GTDN2X2TZYF2HZK6LSD37BXPJAVCNFSM6AAAAACNLU57IKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTKOBZHAZDAMRRHA> > . > You are receiving this because you are subscribed to this thread.Message > ID: ***@***.***> >
Author
Owner

@jslno commented on GitHub (Nov 30, 2025):

Unfortunately I couldn't reproduce the issue. Can you provide a minimal reproduction?

@jslno commented on GitHub (Nov 30, 2025): Unfortunately I couldn't reproduce the issue. Can you provide a minimal reproduction?
Author
Owner

@elecrenPLB commented on GitHub (Dec 1, 2025):

Hello,

I will start by sharing my code, my tests, and the errors I encounter.
If necessary, I will try to create a CodeSandbox project but it requires more setup.

This is a Next.js 16 project.
I use Prisma with SQL Server.
I started experiencing this issue when I upgraded my project to Prisma 7, so I thought this was the problem, but I didn't check that I had also upgraded Better Auth to 1.4.0.

After investigating, I found that the problem is with Better Auth > 1.4.0.

Auth Configuration

Here is my auth configuration:

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: 'sqlserver'
  }),
  trustedOrigins: env.TRUSTED_ORIGINS || [],
  databaseHooks: {
    session: {
      create: {
        before: async (session, context) => {
          const activeAccountId = context?.headers?.get('x-active-account-id')

          if (activeAccountId) {
            return {
              data: {
                ...session,
                activeAccountId: activeAccountId
              }
            }
          }

          return false
        }
      }
    }
  },
  user: {
    modelName: 'CustomerUser',
    deleteUser: {
      enabled: true
    }
  },
  session: {
    modelName: 'CustomerSession',
    additionalFields: {
      activeAccountId: {
        type: 'string',
        required: true,
        description: 'The ID of the selected Salesforce account'
      }
    }
  },
  account: {
    modelName: 'CustomerAccount'
  },
  verification: {
    modelName: 'CustomerVerification'
  },
  emailAndPassword: {
    enabled: true
  },
  plugins: [
    emailOTP({
      async sendVerificationOTP({ email, otp, type }) {
        if (type === 'email-verification') {
          const templatePath = path.join(
            process.cwd(),
            'emails',
            'email-validation-otp.hbs'
          )
          const templateContent = fs.readFileSync(templatePath, 'utf8')
          const template = Handlebars.compile(templateContent)

          const html = template({
            code: otp
          })

          await sendMail({
            to: email,
            from: env.MAIL_SENDER,
            subject: 'Vérification de votre email',
            html: html
          })
        }
      }
    })
  ]
})

Prisma Schema

This is my Prisma schema:

model CustomerAccount {
  id String @id
  accountId String
  providerId String
  userId String
  accessToken String?
  refreshToken String?
  idToken String?
  accessTokenExpiresAt DateTime?
  refreshTokenExpiresAt DateTime?
  scope String?
  password String?
  createdAt DateTime @default(now())
  updatedAt DateTime
  customeruser CustomerUser @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("CustomerAccount")
}

model CustomerSession {
  id String @id
  expiresAt DateTime
  token String @unique
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  ipAddress String?
  userAgent String?
  userId String
  activeAccountId String
  customeruser CustomerUser @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("CustomerSession")
}

model CustomerUser {
  id String @id
  name String
  email String @unique
  emailVerified Boolean @default(false)
  image String?
  createdAt DateTime @default(now())
  updatedAt DateTime @default(now()) @updatedAt
  customeraccounts CustomerAccount[]
  customersessions CustomerSession[]

  @@map("CustomerUser")
}

model CustomerVerification {
  id String @id
  identifier String
  value String
  expiresAt DateTime
  createdAt DateTime @default(now())
  updatedAt DateTime @default(now()) @updatedAt

  @@map("CustomerVerification")
}

Auth Client Configuration

This is my authClient configuration:

export const authClient = createAuthClient({
  //you can pass client configuration here
  baseURL: `${env.NEXT_PUBLIC_APPLICATION_URL}/api/auth`,
  plugins: [emailOTPClient(), inferAdditionalFields<typeof auth>()]
})

Email OTP Sending

I send the email OTP this way:

function handleSendVerificationCode(email: string, contacts: Contact[]) {
  setIsSendingOtp(true)
  authClient.emailOtp.sendVerificationOtp(
    {
      email,
      type: 'email-verification'
    },
    {
      onSuccess: () => {
        toast.success('Code de vérification envoyé', {
          icon: '✉️'
        })
        setEmail(email)
        setContacts(contacts)
        setStep(2)
      },
      onError: () => {
        toast.error(
          "Une erreur est survenue lors de l'envoi du code de vérification",
          {
            icon: '🚫'
          }
        )
      },
      onResponse: () => {
        setIsSendingOtp(false)
      }
    }
  )
}

Issue Description

With Better Auth 1.3.34, it works perfectly and the tests pass.

However, if I upgrade to Better Auth 1.4.0 or above (for example, version 1.4.4):

pnpm up better-auth@latest

I get this error:

Error [PrismaClientValidationError]:
Invalid `db[model].delete()` invocation in
/home/elecren/Projets/espace-clients/.next/dev/server/chunks/0e634*better-auth_dist_54b9ec7c.*.js:5293:47

5290 if (!db[model]) throw new **TURBOPACK**imported**module**$5b$project$5d2f$node*modules$2f2e$pnpm$2f40$better$2d$auth$2b$core$40$1$2e$4$2e$4*$40$better$2d$auth$2b$utils$40$0$2e$3$2e$0_$40$better$2d$fetch$2b$fetch$40$1$2e$1$2e$18_better$2d$call_b1ba4acdd2d2f64b2a3f700d3d58e81e$2f$node_modules$2f40$better$2d$auth$2f$core$2f$dist$2f$error$2d$BhAKg8LX$2e$mjs**$5b$app$2d$route$5d$**$28$ecmascript$29$**$3c$export**t**as**BetterAuthError$3e$\_\_["BetterAuthError"](`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`);
5291 const whereClause = convertWhereClause(model, where);
5292 try {
→ 5293 await db[model].delete({
  where: {
    identifier: "email-verification-otp-mail@mail.fr",
    ? id?: String,
    ? AND?: CustomerVerificationWhereInput | CustomerVerificationWhereInput[],
    ? OR?: CustomerVerificationWhereInput[],
    ? NOT?: CustomerVerificationWhereInput | CustomerVerificationWhereInput[],
    ? value?: StringFilter | String,
    ? expiresAt?: DateTimeFilter | DateTime,
    ? createdAt?: DateTimeFilter | DateTime,
    ? updatedAt?: DateTimeFilter | DateTime
  }
})

Argument `where` of type CustomerVerificationWhereUniqueInput needs at least one of `id` arguments. Available options are marked with ?.
at ignore-listed frames {
  clientVersion: '6.19.0'
}

I think that for the initial issue report, I added a unique constraint to the "identifier" field in the CustomerVerification table for testing purpose, and when I did this, I stopped getting the error, but the function sendVerificationOTP was never called.

To clarify once again: exactly the same code works perfectly with Better Auth < 1.4.0.

@elecrenPLB commented on GitHub (Dec 1, 2025): Hello, I will start by sharing my code, my tests, and the errors I encounter. If necessary, I will try to create a CodeSandbox project but it requires more setup. This is a Next.js 16 project. I use Prisma with SQL Server. I started experiencing this issue when I upgraded my project to Prisma 7, so I thought this was the problem, but I didn't check that I had also upgraded Better Auth to 1.4.0. After investigating, I found that the problem is with Better Auth > 1.4.0. ## Auth Configuration Here is my auth configuration: ```typescript export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: 'sqlserver' }), trustedOrigins: env.TRUSTED_ORIGINS || [], databaseHooks: { session: { create: { before: async (session, context) => { const activeAccountId = context?.headers?.get('x-active-account-id') if (activeAccountId) { return { data: { ...session, activeAccountId: activeAccountId } } } return false } } } }, user: { modelName: 'CustomerUser', deleteUser: { enabled: true } }, session: { modelName: 'CustomerSession', additionalFields: { activeAccountId: { type: 'string', required: true, description: 'The ID of the selected Salesforce account' } } }, account: { modelName: 'CustomerAccount' }, verification: { modelName: 'CustomerVerification' }, emailAndPassword: { enabled: true }, plugins: [ emailOTP({ async sendVerificationOTP({ email, otp, type }) { if (type === 'email-verification') { const templatePath = path.join( process.cwd(), 'emails', 'email-validation-otp.hbs' ) const templateContent = fs.readFileSync(templatePath, 'utf8') const template = Handlebars.compile(templateContent) const html = template({ code: otp }) await sendMail({ to: email, from: env.MAIL_SENDER, subject: 'Vérification de votre email', html: html }) } } }) ] }) ``` ## Prisma Schema This is my Prisma schema: ```prisma model CustomerAccount { id String @id accountId String providerId String userId String accessToken String? refreshToken String? idToken String? accessTokenExpiresAt DateTime? refreshTokenExpiresAt DateTime? scope String? password String? createdAt DateTime @default(now()) updatedAt DateTime customeruser CustomerUser @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("CustomerAccount") } model CustomerSession { id String @id expiresAt DateTime token String @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt ipAddress String? userAgent String? userId String activeAccountId String customeruser CustomerUser @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("CustomerSession") } model CustomerUser { id String @id name String email String @unique emailVerified Boolean @default(false) image String? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt customeraccounts CustomerAccount[] customersessions CustomerSession[] @@map("CustomerUser") } model CustomerVerification { id String @id identifier String value String expiresAt DateTime createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("CustomerVerification") } ``` ## Auth Client Configuration This is my authClient configuration: ```typescript export const authClient = createAuthClient({ //you can pass client configuration here baseURL: `${env.NEXT_PUBLIC_APPLICATION_URL}/api/auth`, plugins: [emailOTPClient(), inferAdditionalFields<typeof auth>()] }) ``` ## Email OTP Sending I send the email OTP this way: ```typescript function handleSendVerificationCode(email: string, contacts: Contact[]) { setIsSendingOtp(true) authClient.emailOtp.sendVerificationOtp( { email, type: 'email-verification' }, { onSuccess: () => { toast.success('Code de vérification envoyé', { icon: '✉️' }) setEmail(email) setContacts(contacts) setStep(2) }, onError: () => { toast.error( "Une erreur est survenue lors de l'envoi du code de vérification", { icon: '🚫' } ) }, onResponse: () => { setIsSendingOtp(false) } } ) } ``` ## Issue Description With Better Auth 1.3.34, it works perfectly and the tests pass. However, if I upgrade to Better Auth 1.4.0 or above (for example, version 1.4.4): ```bash pnpm up better-auth@latest ``` I get this error: ``` Error [PrismaClientValidationError]: Invalid `db[model].delete()` invocation in /home/elecren/Projets/espace-clients/.next/dev/server/chunks/0e634*better-auth_dist_54b9ec7c.*.js:5293:47 5290 if (!db[model]) throw new **TURBOPACK**imported**module**$5b$project$5d2f$node*modules$2f2e$pnpm$2f40$better$2d$auth$2b$core$40$1$2e$4$2e$4*$40$better$2d$auth$2b$utils$40$0$2e$3$2e$0_$40$better$2d$fetch$2b$fetch$40$1$2e$1$2e$18_better$2d$call_b1ba4acdd2d2f64b2a3f700d3d58e81e$2f$node_modules$2f40$better$2d$auth$2f$core$2f$dist$2f$error$2d$BhAKg8LX$2e$mjs**$5b$app$2d$route$5d$**$28$ecmascript$29$**$3c$export**t**as**BetterAuthError$3e$\_\_["BetterAuthError"](`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`); 5291 const whereClause = convertWhereClause(model, where); 5292 try { → 5293 await db[model].delete({ where: { identifier: "email-verification-otp-mail@mail.fr", ? id?: String, ? AND?: CustomerVerificationWhereInput | CustomerVerificationWhereInput[], ? OR?: CustomerVerificationWhereInput[], ? NOT?: CustomerVerificationWhereInput | CustomerVerificationWhereInput[], ? value?: StringFilter | String, ? expiresAt?: DateTimeFilter | DateTime, ? createdAt?: DateTimeFilter | DateTime, ? updatedAt?: DateTimeFilter | DateTime } }) Argument `where` of type CustomerVerificationWhereUniqueInput needs at least one of `id` arguments. Available options are marked with ?. at ignore-listed frames { clientVersion: '6.19.0' } ``` I think that for the initial issue report, I added a unique constraint to the "identifier" field in the CustomerVerification table for testing purpose, and when I did this, I stopped getting the error, but the function `sendVerificationOTP` was never called. To clarify once again: exactly the same code works perfectly with Better Auth < 1.4.0.
Author
Owner

@himself65 commented on GitHub (Dec 1, 2025):

/cc @ping-maxwell

@himself65 commented on GitHub (Dec 1, 2025): /cc @ping-maxwell
Author
Owner

@himself65 commented on GitHub (Dec 1, 2025):

Have you followed the https://www.prisma.io/docs/guides/betterauth-nextjs?

@himself65 commented on GitHub (Dec 1, 2025): Have you followed the https://www.prisma.io/docs/guides/betterauth-nextjs?
Author
Owner

@elecrenPLB commented on GitHub (Dec 2, 2025):

Hello,

I have not followed this specific guide but after reading it, I have done exactly the same.

My code works perfectly even with Prisma 7, if I use Better-Auth < 1.4.0
(Currently 1.3.34)

It does not work with Better-Auth >= 1.4.0

@elecrenPLB commented on GitHub (Dec 2, 2025): Hello, I have not followed this specific guide but after reading it, I have done exactly the same. My code works perfectly even with Prisma 7, if I use Better-Auth < 1.4.0 (Currently 1.3.34) It does not work with Better-Auth >= 1.4.0
Author
Owner

@himself65 commented on GitHub (Dec 2, 2025):

Hi, I'm invesgating this

@himself65 commented on GitHub (Dec 2, 2025): Hi, I'm invesgating this
Author
Owner

@himself65 commented on GitHub (Dec 2, 2025):

Closed a wrong issue

@himself65 commented on GitHub (Dec 2, 2025): Closed a wrong issue
Author
Owner

@Fouadktb commented on GitHub (Dec 9, 2025):

@himself65 also encountring same issue after 1.4.0, had to go back to 1.3.34.

it seems that the handler in the client is not being called at all

@Fouadktb commented on GitHub (Dec 9, 2025): @himself65 also encountring same issue after 1.4.0, had to go back to 1.3.34. it seems that the handler in the client is not being called at all
Author
Owner

@mahmoodfathy commented on GitHub (Jan 16, 2026):

Having the same issue as well on V1.4.7

PrismaClientValidationError: 
 Invalid `prisma.verification.delete()` invocation:

 {
   where: {
     identifier: "forget-password-otp-test@test.com",
 ?   id?: String,
 ?   AND?: VerificationWhereInput | VerificationWhereInput[],
 ?   OR?: VerificationWhereInput[],
 ?   NOT?: VerificationWhereInput | VerificationWhereInput[],
 ?   value?: StringFilter | String,
 ?   expiresAt?: DateTimeFilter | DateTime,
?   createdAt?: DateTimeFilter | DateTime,
?   updatedAt?: DateTimeFilter | DateTime
  }
 }

if add the unique constraint: identifier String @unique nothing gets ran and the api returns succes

@mahmoodfathy commented on GitHub (Jan 16, 2026): Having the same issue as well on V1.4.7 ``` PrismaClientValidationError: Invalid `prisma.verification.delete()` invocation: { where: { identifier: "forget-password-otp-test@test.com", ? id?: String, ? AND?: VerificationWhereInput | VerificationWhereInput[], ? OR?: VerificationWhereInput[], ? NOT?: VerificationWhereInput | VerificationWhereInput[], ? value?: StringFilter | String, ? expiresAt?: DateTimeFilter | DateTime, ? createdAt?: DateTimeFilter | DateTime, ? updatedAt?: DateTimeFilter | DateTime } } ``` if add the unique constraint: ` identifier String @unique` nothing gets ran and the api returns succes
Author
Owner

@realfish commented on GitHub (Mar 2, 2026):

Encountered similar issue on v1.5.1.

The Magic Link auth links trigger server errors like:

  5221     where,
  5222     action: "update"
  5223 });
→ 5224 return await db[model].update({
         where: {
           identifier: "bLbZMdYTmYiQBhcTvxVxHbhGZDBWOzkW",
       ?   id?: String,
       ?   AND?: VerificationWhereInput | VerificationWhereInput[],
       ?   OR?: VerificationWhereInput[],
       ?   NOT?: VerificationWhereInput | VerificationWhereInput[],
       ?   value?: StringFilter | String,
       ?   expiresAt?: DateTimeFilter | DateTime,
       ?   createdAt?: DateTimeNullableFilter | DateTime | Null,
       ?   updatedAt?: DateTimeNullableFilter | DateTime | Null
         },
         data: {
           value: "{\"email\":\"xxxx@xxxxx.com\",\"attempt\":1}",
           updatedAt: new Date("2026-03-02T15:11:11.796Z")
         }
       })

Argument `where` of type VerificationWhereUniqueInput needs at least one of `id` arguments. Available options are marked with ?.
    at async GET (app/api/auth/[...all]/route.ts:16:22)

After adding identifier String @unique constraint to Verification table, the issue was fixed.

@realfish commented on GitHub (Mar 2, 2026): Encountered similar issue on v1.5.1. The Magic Link auth links trigger server errors like: ``` 5221 where, 5222 action: "update" 5223 }); → 5224 return await db[model].update({ where: { identifier: "bLbZMdYTmYiQBhcTvxVxHbhGZDBWOzkW", ? id?: String, ? AND?: VerificationWhereInput | VerificationWhereInput[], ? OR?: VerificationWhereInput[], ? NOT?: VerificationWhereInput | VerificationWhereInput[], ? value?: StringFilter | String, ? expiresAt?: DateTimeFilter | DateTime, ? createdAt?: DateTimeNullableFilter | DateTime | Null, ? updatedAt?: DateTimeNullableFilter | DateTime | Null }, data: { value: "{\"email\":\"xxxx@xxxxx.com\",\"attempt\":1}", updatedAt: new Date("2026-03-02T15:11:11.796Z") } }) Argument `where` of type VerificationWhereUniqueInput needs at least one of `id` arguments. Available options are marked with ?. at async GET (app/api/auth/[...all]/route.ts:16:22) ``` After adding `identifier String @unique` constraint to `Verification` table, the issue was fixed.
Author
Owner

@Glovvie commented on GitHub (Mar 2, 2026):

I started encountering prisma "Argument where of type VerificationWhereUniqueInput needs at least one of id arguments." issue in 1.5.1

Adding identifier String @unique constraint to the Verification table seems to have fixed the issue.
Is this actually a valid workaround?

@Glovvie commented on GitHub (Mar 2, 2026): I started encountering prisma "Argument `where` of type VerificationWhereUniqueInput needs at least one of `id` arguments." issue in 1.5.1 Adding identifier String @unique constraint to the Verification table seems to have fixed the issue. Is this actually a valid workaround?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2407