PrismaClientKnownRequestError: Unique constraint failed on the fields: (`email`)

Node.js · updated 2026-11-03

Thrown by Prisma Client on create, update or upsert when the database rejects a duplicate value. error.code is 'P2002' and error.meta.target names the fields of the unique index that blocked it.

PrismaClientKnownRequestError:
Invalid `prisma.user.create()` invocation:

Unique constraint failed on the fields: (`email`)
    at Zn.handleRequestError (/app/node_modules/@prisma/client/runtime/library.js:121:7315)
    at async signup (file:///app/src/auth.js:22:16) {
  code: 'P2002',
  clientVersion: '6.x',
  meta: { modelName: 'User', target: [ 'email' ] }
}

Quick fix

Decide what a duplicate means for this operation. For signups, catch P2002 and return a clear 409 ("email already registered"). For idempotent writes, use upsert or connectOrCreate. Don't check-then-insert: two requests can both pass the check.

  1. Read meta.target to see which unique fields collided.
  2. Catch the error by code: err instanceof Prisma.PrismaClientKnownRequestError && err.code === 'P2002'.
  3. Return a 409 with a message the user can act on, instead of a 500.
  4. For create-or-update flows, switch to prisma.model.upsert().
  5. Normalize values before saving (lowercase emails, trim) so "A@x.com" and "a@x.com" do not slip past your own check but hit a case-insensitive index.
typescript
import { Prisma } from '@prisma/client';

try {
  return await prisma.user.create({ data: { email: email.trim().toLowerCase(), name } });
} catch (err) {
  if (err instanceof Prisma.PrismaClientKnownRequestError && err.code === 'P2002') {
    throw new HttpError(409, 'An account with this email already exists');
  }
  throw err;
}

// Idempotent write: no race between "exists?" and "insert"
await prisma.subscription.upsert({
  where: { stripeId },
  create: { stripeId, userId, status },
  update: { status },
});

Why it happens

Double submits and retries

A user clicking twice, a client retrying after a timeout, or a webhook delivered twice runs the same insert again. The second one hits the unique index.

Check-then-insert races

findUnique followed by create leaves a gap where another request can insert the same value. Under load this produces intermittent P2002 errors.

Values that differ only in format

Unnormalized emails or usernames (case, whitespace) can pass an application check and still collide on the database index, or the other way round.

Seed or migration scripts run twice

Seeding with create instead of upsert fails the second time it runs against the same database.

Other fixes

  • Use createMany({ skipDuplicates: true }) for bulk imports where duplicates should be ignored.
  • Store an idempotency key for webhook and payment handlers so repeats are recognized before they write.

Same error, other wording

  • Unique constraint failed on the constraint: `User_email_key`
  • PrismaClientKnownRequestError: Unique constraint failed on the fields: (`orderId`,`lineNumber`)
  • Error: duplicate key value violates unique constraint "users_email_key"

Let your coding agent catch the next one

Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:

> Find the Prisma P2002 unique constraint errors in production, group them by model and target fields, tell me which come from retries or double submits, and switch those writes to upsert or a handled 409.

Plans from $29/moSee what your agent readsSee the setupCancel any time from the billing portal

Related errors

References: Prisma docs: error reference (P2002), Prisma docs: handling exceptions and errors