On this page

← Blog
Engineering5 min read

Fix Django IntegrityError: UNIQUE, NOT NULL, and Foreign Key Violations

Django IntegrityError means a database write violated a constraint. Here are the 4 most common causes: duplicate unique fields, migration issues, race conditions, missing required fields, and the exact fix for each.

djangointegrityerrorpostgresqldatabasepython

Django throws IntegrityError when a database write violates a constraint. The error is raised at the database level, so it bypasses any model-level validation you have in place.

There are four common causes. Each one has a different fix.

Reading the Error

django.db.utils.IntegrityError: UNIQUE constraint failed: myapp_user.email

Three things to read off this:

  • myapp_user is the database table (app name + model name, lowercase)
  • email is the column with the UNIQUE constraint
  • The duplicate value is not shown in the message — you have to find it yourself

Cause 1: Duplicate Value in a Unique Field

python
class User(models.Model):
    email = models.EmailField(unique=True)

Saving two users with the same email triggers IntegrityError. Use get_or_create to avoid the collision:

python
user, created = User.objects.get_or_create(
    email=email,
    defaults={'name': name}
)

if not created:
    # user already exists — handle accordingly
    pass

Or catch the error explicitly:

python
from django.db import IntegrityError

try:
    User.objects.create(email=email, name=name)
except IntegrityError:
    return JsonResponse({'error': 'Email already registered'}, status=409)

Fix: Use get_or_create when inserting records that have a unique constraint. It removes the need for a manual existence check.

Cause 2: Migration Added a Unique Constraint to Existing Data

You add unique=True to a field that already has duplicate values. Running python manage.py migrate fails:

django.db.utils.IntegrityError: could not create unique index "myapp_user_email_key"
DETAIL:  Key (email)=(user@example.com) is duplicated.

Clean up duplicates before applying the migration:

python
# Run in Django shell before migrating
from myapp.models import User
from django.db.models import Count

duplicates = (User.objects
    .values('email')
    .annotate(count=Count('id'))
    .filter(count__gt=1))

for dup in duplicates:
    print(dup)  # review before deleting

Warning: Delete or merge duplicates first. Running the migration before cleaning up will fail at the database level and cannot be resolved by Django alone.

Cause 3: Race Condition Under Concurrent Requests

Two requests arrive at the same time. Both check whether the email exists, both see nothing, both try to insert. One wins. The other gets IntegrityError.

The fix is to stop using check-then-insert. Let the database enforce uniqueness and catch the error when it fires:

python
# Prone to race conditions
if not User.objects.filter(email=email).exists():
    User.objects.create(email=email)
python
# Safe — DB enforces uniqueness, catch the violation
from django.db import IntegrityError

try:
    user = User.objects.create(email=email)
except IntegrityError:
    user = User.objects.get(email=email)

Note: The database unique constraint is the only reliable guard against concurrent inserts. Application-level checks are not atomic.

Cause 4: NOT NULL Constraint on a Required Field

django.db.utils.IntegrityError: NOT NULL constraint failed: myapp_order.user_id

A foreign key or required field is None at save time:

python
order = Order(total=99.99)  # user is missing
order.save()                 # IntegrityError

Set the required field before saving:

python
order = Order(total=99.99, user=request.user)
order.save()

If the field should be optional at the database level:

python
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)

Finding the Duplicate Value

The error message does not include the offending value. Find it in the shell:

bash
python manage.py shell
python
from myapp.models import User
from django.db.models import Count

User.objects.values('email').annotate(n=Count('id')).filter(n__gt=1)

IntegrityError Types at a Glance

Error textCauseFix
UNIQUE constraint failedDuplicate value in unique fieldget_or_create or dedup existing data
NOT NULL constraint failedRequired field is NoneSet the field before saving
FOREIGN KEY constraint failedReferenced record does not existCreate the parent record first
CHECK constraint failedValue outside allowed rangeCheck model validators

FAQ

Q: Why does IntegrityError bypass my model's clean() method?

A: clean() runs during form validation, not during direct ORM saves. If you call Model.objects.create() directly, Django skips full_clean(). Call instance.full_clean() before instance.save() if you want model-level validation on direct saves.

Q: Can I catch IntegrityError for bulk inserts?

A: Yes. Use bulk_create with ignore_conflicts=True to skip duplicates silently. Note that it does not return the existing records, only the ones that were inserted.

python
User.objects.bulk_create(users, ignore_conflicts=True)

For IntegrityError in complex transactions — bulk inserts, signals that trigger saves, or Celery tasks writing concurrently — paste the model and the failing view into DebugAI and it will trace the exact constraint violation.

Debug faster starting today.

Free VS Code extension · 10 sessions/day · no credit card

Install free →

Related posts

Engineering

Nothing checked that fix.

6 min read

Engineering

We built a test harness for our own AI debugger. The harness had more bugs than the debugger.

6 min read

← All posts