Fix Django IntegrityError: UNIQUE Constraint Failed -> 5 Causes and Fixes
Django IntegrityError means a database constraint was violated. Here are the 5 most common causes: duplicate records, missing migrations, race conditions, and the exact fix for each.
What Is Django IntegrityError?
Django raises IntegrityError when a database operation violates a constraint: UNIQUE, NOT NULL, FOREIGN KEY, or CHECK. Django does not catch these automatically. They bubble up as unhandled exceptions unless you wrap the database call.
Error:
django.db.utils.IntegrityError: UNIQUE constraint failed: auth_user.username
The error always includes the table name and column name after the colon. That is your starting point. Find which model maps to that table, find which field has the constraint, and trace back to where you are writing that field.
Cause 1: Duplicate Value on a UNIQUE Field
Most common cause. You are inserting or updating a record with a value that already exists on a field marked unique=True.
Use get_or_create when you want "create if not exists", or update_or_create for upsert behavior:
Cause 2: Missing or Unapplied Migration After Model Change
Adding unique=True to an existing field, or adding a new unique constraint, requires a migration. If you forget to run it, the database schema and your Django model disagree. Inserts that Django thinks are valid fail at the database level.
Error:
django.db.utils.IntegrityError: UNIQUE constraint failed: myapp_product.sku
Check migration status first:
If the constraint was added to an existing field with existing data, handle duplicates before migrating:
Cause 3: Race Condition on Concurrent Inserts
Two requests arrive at the same time. Both check whether the username exists, both get False, both try to insert. One succeeds. The other raises IntegrityError. The UNIQUE constraint is doing its job. The bug is the check-then-insert pattern.
Do not check first. Try the insert and catch IntegrityError:
Note: This pattern, try insert then catch and get, is safe under concurrent load.
get_or_createdoes the same thing internally using atomic transactions depending on the database backend.
Cause 4: NOT NULL Constraint on a Field Without a Default
Adding a new required field to an existing model without providing a default fails when existing rows are migrated. Django prompts you during makemigrations, but if you bypass the prompt or script migrations manually, the NOT NULL violation hits at migration time.
Error:
django.db.utils.IntegrityError: NOT NULL constraint failed: myapp_order.customer_id
Add the field as nullable first, then backfill, then remove the null:
Cause 5: FOREIGN KEY Violation
Inserting a row that references a non-existent parent record. Common when creating related objects out of order, or when the parent was deleted and on_delete was not set correctly.
Error:
django.db.utils.IntegrityError: insert or update on table "myapp_order" violates foreign key constraint
Validate the parent exists before creating the child:
How to Catch IntegrityError Gracefully
In views and API handlers, wrap database operations to return a useful error instead of a 500:
Quick Reference
| IntegrityError type | Cause | Fix |
|---|---|---|
UNIQUE constraint failed | Duplicate value on unique field | get_or_create or catch and return existing |
NOT NULL constraint failed | Field missing value, no default | Add default or use nullable migration |
| Foreign key violation | Parent record does not exist | Validate parent ID before insert |
| Check constraint violation | Value outside allowed range | Validate at model level before saving |
For race condition bugs specifically, IntegrityError that appears under load but not locally, paste the view and model into DebugAI. It identifies check-then-insert patterns and suggests the atomic equivalent.
Debug faster starting today.
Free VS Code extension. 10 sessions/day. No credit card.