My FastAPI app (CENCO Platform) is failing to deploy
tribalnotes
PROOP

10 days ago

My FastAPI app (CENCO Platform) is failing to deploy due to a database migration conflict.

Error: Migration 20260718_0060 (Document extractions) tries to create table document_extractions, but the table already exists.

psycopg.errors.DuplicateTable: relation "document_extractions" already exists

Project: Chifi (69b63ff2-4a55-48cd-8dd4-11d5d670cc06)

Environment: production

Service: CENCO Platform (tribalnotes/Chifi repo, main branch)

Database: PostgreSQL service (7cfa81c2-1188-4e50-8bfa-dcbe3c1bff62)

The app can't deploy because the pre-deploy migration always fails. The table exists in the database but Alembic's alembic_version table doesn't have a record that the migration completed.

Need help marking migration 20260718_0060 as complete in the migration history, or verifying/resetting the table schema.

$20 Bounty

2 Replies

Railway
BOT

10 days ago

This thread has been opened as a public bounty so the community can help solve it. The thread and any further activity are now visible to everyone.

Status changed to Open Railway 10 days ago


10 days ago

  1. Verify the document_extractions table schema matches the migration.

  2. Connect to your PostgreSQL service (7cfa81c2-1188-4e50-8bfa-dcbe3c1bff62) via the Railway Data view, psql, or pgAdmin.

Run the following SQL query to manually update the tracking table:

 DELETE FROM alembic_version;

 INSERT INTO alembic_version (version_num) VALUES ('20260718_0060');

myiephero
HOBBY

2 hours ago

h701h's direction is right, but I'd avoid running that SQL as written and I'd do one check before stamping anything.

Two problems with DELETE FROM alembic_version then INSERT. First, alembic_version can legitimately hold more than one row when a project has multiple heads, and deleting everything silently discards that. Second, it writes the version whether or not the schema is actually correct — which is the part that bites you later.

Use Alembic's own command instead, which handles the head bookkeeping properly:

alembic stamp 20260718_0060

But verify first, because stamping is a promise to Alembic that the schema already matches. If it doesn't, every future migration builds on a wrong assumption and you get a much more confusing failure weeks from now.

The check, from your repo with the service's environment injected:

railway run alembic current

railway run alembic history | head -20

Then compare the live table against what the migration would have built. In psql:

\d document_extractions

and read the op.create_table block in versions/20260718_0060_*.py side by side. Columns, types, nullability, indexes, constraints.

Then it splits two ways:

Schema matches — stamp it and move on:

railway run alembic stamp 20260718_0060

railway run alembic upgrade head

Schema does NOT match — do not stamp. Check whether the table has data first:

SELECT count(*) FROM document_extractions;

If it's empty, drop it and let the migration create it properly:

DROP TABLE document_extractions;

then redeploy and the pre-deploy migration runs clean. If it does have rows, write a corrective migration to reconcile the differences rather than dropping anything.

On the root cause, because otherwise this recurs on the next model you add:

A table existing while alembic_version has no record of it is the classic signature of SQLAlchemy's Base.metadata.create_all() running somewhere in your app startup. Postgres has transactional DDL, so a migration that failed partway would have rolled the CREATE TABLE back with it — the table would not have survived. Something outside Alembic created it. In FastAPI codebases that's almost always a create_all() call in a lifespan handler, main.py, or a db init module, left over from early development.

If you find one, delete it. Alembic and create_all() managing the same schema will keep colliding, and it'll be a different table next time.

Worth grepping for:

grep -rn "create_all" .

One more thing given this is production and pre-deploy is currently failing: pre-deploy failing means the old deployment keeps serving, so you're not down — but it also means nothing new ships until this clears. Sort the schema question before stamping rather than stamping to unblock the pipeline, because an incorrect stamp is much harder to unwind than a few more hours on the previous release.


Welcome!

Sign in to your Railway account to join the conversation.

Loading...