psycopg.errors.UniqueViolation: duplicate key value violates unique constraint "users_email_key"
Python · updated 2026-11-03
Raised by psycopg (psycopg2.errors.UniqueViolation) and wrapped by SQLAlchemy as IntegrityError and by Django as IntegrityError, when an INSERT or UPDATE would duplicate a value in a unique index. The DETAIL line names the column and value.
Traceback (most recent call last): ... psycopg.errors.UniqueViolation: duplicate key value violates unique constraint "users_email_key" DETAIL: Key (email)=(ada@example.com) already exists. The above exception was the direct cause of the following exception: ... sqlalchemy.exc.IntegrityError: (psycopg.errors.UniqueViolation) duplicate key value violates unique constraint "users_email_key"
Quick fix
Handle the duplicate where it happens: catch IntegrityError (SQLAlchemy or Django), roll back the session, and return a 409 or a friendly message. For create-or-update logic, use INSERT ... ON CONFLICT (or the ORM equivalent) so the database decides atomically.
- Read the DETAIL line: it names the column and the duplicate value.
- Catch the IntegrityError and roll back the transaction before doing anything else in that session.
- Return a specific error to the user instead of a 500.
- Replace "select, then insert" with an upsert: INSERT ... ON CONFLICT (email) DO UPDATE / DO NOTHING.
- If the error mentions a primary key on a table you inserted ids into manually, reset the sequence (setval).
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.exc import IntegrityError
try:
session.add(User(email=email.strip().lower(), name=name))
session.commit()
except IntegrityError:
session.rollback()
raise HTTPException(status_code=409, detail="An account with this email already exists")
# Upsert: let Postgres resolve the conflict atomically
stmt = insert(Subscription).values(stripe_id=sid, status=status)
stmt = stmt.on_conflict_do_update(index_elements=["stripe_id"], set_={"status": status})
session.execute(stmt)
session.commit()Why it happens
Retries and double submits
A retried request, a repeated webhook or a double-clicked form runs the same insert twice; the second one violates the unique index.
Check-then-insert races
Two requests both see "no row yet" and both insert. Only a database constraint or an upsert closes that gap.
Primary key sequence out of sync
After importing rows with explicit ids or restoring a dump, the id sequence can lag behind, so new inserts reuse an existing id ("Key (id)=(1042) already exists").
Format differences in the value
Case or whitespace differences let two "different" values through your code that collide on a case-insensitive or normalized unique index.
Other fixes
- In Django, use get_or_create or update_or_create, and catch IntegrityError around them under concurrency.
- Fix a lagging sequence with SELECT setval(pg_get_serial_sequence('users', 'id'), max(id)) FROM users;
Same error, other wording
- psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "orders_pkey"
- django.db.utils.IntegrityError: duplicate key value violates unique constraint "accounts_user_username_key"
- sqlite3.IntegrityError: UNIQUE constraint failed: users.email
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 duplicate key / IntegrityError errors in production, group them by constraint name, tell me which are races or retries and which are sequence problems, and fix each with an upsert, a handled 409 or a sequence reset.
Related errors
- psycopg2.OperationalError: server closed the connection unexpectedly
- django.db.utils.OperationalError: no such table: orders_order
- KeyError: 'email'
References: PostgreSQL docs: INSERT ... ON CONFLICT, SQLAlchemy docs: PostgreSQL INSERT ... ON CONFLICT