Skip to content
Latchkey

Alembic "FAILED: relation already exists" in CI

A migration’s create_table or create_index hit an object the database already has. The DDL is valid, but the target database is not in the state the migration expects.

What this error means

alembic upgrade head fails partway with a database "already exists" error wrapped by Alembic. It commonly appears when migrations run against a database that already has the schema, or after a partial earlier run.

alembic output
FAILED: (psycopg2.errors.DuplicateTable) relation "orders" already exists

[SQL: CREATE TABLE orders (...)]

Common causes

Running against a non-clean database

The schema (or part of it) was created already - by a previous run, a hand-built database, or a stamp without the matching upgrade - so the create fails.

alembic_version out of sync with schema

If the version table says a revision did not run but the objects exist, Alembic re-runs the create and collides with the existing relation.

A partially applied earlier migration

An interrupted upgrade created some objects but did not advance the version pointer, so the next run re-creates them.

How to fix it

Start from a clean database in CI

Apply the full migration chain against an empty database so every create runs exactly once.

Terminal
# drop & recreate the CI database, then upgrade
dropdb --if-exists app_test && createdb app_test
alembic upgrade head

Reconcile the version pointer

  1. Check alembic current against what objects actually exist.
  2. If the schema already matches a revision, alembic stamp <revision> to record it without re-running DDL.
  3. Then alembic upgrade head to apply only the genuinely pending migrations.

Guard creates where re-runs are expected

For idempotent setup paths, create conditionally so an existing object is not an error.

migration.py
op.execute("CREATE TABLE IF NOT EXISTS orders (...)")

How to prevent it

  • Run migrations against an ephemeral, empty database in CI.
  • Keep alembic_version consistent with the real schema; stamp rather than re-run when seeding.
  • Apply each upgrade transactionally so an interruption leaves no partial objects.

Frequently asked questions

What causes ""relation already exists""?
The schema (or part of it) was created already - by a previous run, a hand-built database, or a stamp without the matching upgrade - so the create fails.
How do I fix "relation already exists"?
Apply the full migration chain against an empty database so every create runs exactly once.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card