← Back to list

Why Alembic Shouts “Can’t locate revision …”: The Hidden Trap When OrbStack and Docker Desktop Run…

Why Alembic Shouts “Can’t locate revision …”: The Hidden Trap When OrbStack and Docker Desktop Run Together

Chris Evans in codecodecode · 2025-10-01 17:59 · 0 claps · 4.1 min read
#docker #orbstack #alembic #database
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

Why Alembic Shouts “Can’t locate revision …”: The Hidden Trap When OrbStack and Docker Desktop Run Together

Why Alembic Shouts “Can’t locate revision …”: The Hidden Trap When OrbStack and Docker Desktop Run Together

TL;DR: This isn’t an Alembic “cache” issue. Your app is connecting to the wrong Postgres instance, whose alembic_versionstill points to a revision that no longer exists in your repository (e.g., 0997d75093b0). When OrbStack and Docker Desktop are both running, you can end up with two separate Postgres + volumes that look similar (same host/port), and your app silently hits the older one. Alembic then tries to resolve a DB head that isn’t present in your alembic/versions/ anymore and fails with:

alembic.util.exc.CommandError: Can't locate revision identified by '0997d75093b0'

The Story: “I deleted my migrations, why is the error still here?”

You boot FastAPI/Uvicorn. A bootstrap step triggers migrations. Suddenly:

alembic.util.exc.CommandError: Can't locate revision identified by '0997d75093b0'

You even cleared alembic/versions/ and __pycache__, but the error persists. The twist: it only happens when both OrbStack and Docker Desktop are open. That’s the telltale sign that you’re not talking to the DB you think you are.

Background: How Alembic decides “which migrations to run”

  • Before running, Alembic queries the database for its current head from **alembic_version** (or multiple heads in multi-head scenarios).
  • Then it builds a revision graph from the migration files in your repository (alembic/versions/).
  • If the DB’s recorded head doesn’t exist in the filesystem, Alembic can’t walk the graph and throws “Can’t locate revision …”.

So the root cause is DB ↔ repository mismatch, not stale caches.

Why running OrbStack and Docker Desktop makes this more likely

  • Each runtime maintains different Docker contexts, networks, and volumes.
  • Your innocent postgres://localhost:5432 might point to different Postgres instances under different contexts.
  • If both sides happen to bind 5432 (or your compose files don’t pin ports uniquely), the app can silently hit the old DB with an oldvolume.
  • That old volume’s alembic_version could still be 0997d75093b0, while your repo no longer contains that migration script → boom.

A 3‑Minute Triage Checklist (practical and effective)

1) Ensure your CLI is talking to the intended Docker context

docker context ls
docker context use desktop-linux   # or: docker context use orbstack

2) Who is listening on 5432? (detect conflicts and origins)

lsof -iTCP:5432 -sTCP:LISTEN -nP
# Check whether the listener is from orbstack or docker-desktop

3) Ask the DB directly: what’s your Alembic head?

psql "postgresql://USER:PASS@localhost:5432/DBNAME" \
  -c "select * from alembic_version;"
# If you see 0997d75093b0, you’re on the old volume/instance.

Pro tip: If you change your compose’s exposed port (see next section), try psql against that port so you know which instance you’re hitting.

Fix Strategies (choose the one that fits your current goal)

A) Keep your migration files as the source of truth, align the DB (safe & common)

  1. Run only one runtime (close the other, or pin docker context use).
  2. Ensure alembic/versions/ contains the baseline/head you expect.
  3. On the correct DB instance, run:
# If this DB should be treated as "fresh" w.r.t. the current repo state:
alembic stamp head
alembic upgrade head

*stamp head sets the DB’s version to your repo’s current head without running historical diffs. Then upgrade head applies any pending steps.*

B) Clean-room dev reset: drop the data volume and rebuild (fastest for dev)

This deletes data — dev environments only.

docker compose down -v    # remove volumes (data will be wiped)
docker compose up -d
alembic upgrade head

C) Quick unblocking: unpin the “unknown” revision and move forward

# Treat DB as having no revision
alembic stamp base
# Then bring it up to date
alembic upgrade head

Use this if the schema/data aren’t important, or you’re fine treating the DB as freshly initialized.

Long‑Term Guardrails (a.k.a. how to stop this from ever happening again)

1) Pin a single Docker context

Pin it at the top of your Makefile or bootstrap scripts:

docker context use desktop-linux   # or: docker context use orbstack

Or set it in your shell init so you don’t flip-flop unintentionally.

2) Avoid port 5432 collisions (highly recommended)

Give your dev Postgres a unique host port so you always know which instance you’re hitting:

# docker-compose.yml
services:
  db:
    image: postgres:16
    ports:
      - "55432:5432"   # use 55432 externally

Then point your app/DSN to localhost:55432. Even if both runtimes are up, you’ll always land on this instance.

3) Fix the Compose project and volume names

In a .env or compose file:

COMPOSE_PROJECT_NAME=remote_lock_cloud_dev

And give volumes distinct, explicit names to avoid “same-looking name, different runtime” confusion.

4) Fail‑fast sanity check before running migrations (strongly recommended)

Before running migrations, verify that the DB head(s) exist in the repo. Example utility (comments in English by design):

# app/services/db_migration_sanity.py
from alembic.config import Config
from alembic.script import ScriptDirectory
from alembic.runtime.migration import MigrationContext

def assert_db_heads_are_known(engine, alembic_cfg: Config):
    """
    Fail fast if the DB points to unknown Alembic heads.
    """
    script = ScriptDirectory.from_config(alembic_cfg)
    known = {rev.revision for rev in script.walk_revisions()}
    with engine.connect() as conn:
        ctx = MigrationContext.configure(conn)
        current_heads = set(ctx.get_current_heads())
    unknown = current_heads - known
    if unknown:
        raise RuntimeError(
            f"DB has unknown Alembic heads: {unknown}. "
            "Likely connected to the wrong database or missing migration files."
        )

Wiring it into your bootstrap:

if settings.AUTO_MIGRATE:
    assert_db_heads_are_known(engine, cfg)  # fail fast with a clear message
    run_db_migrations()

5) Gate revision --autogenerate behind a flag

Daily runs should only do upgrade. Generate new revisions only when explicitly requested:

AUTO_GENERATE_REVISION=1 make dev   # otherwise skip autogenerate

Common Pitfalls (and why they’re wrong)

  • “Deleting alembic/versions/ will fix it.” No. The DB’s alembic_version still points to an old revision. If the repo can’t see that revision, Alembic will complain — by design.
  • “This must be an Alembic cache bug.” It isn’t. The core problem is mismatch between the database’s recorded state and the repository’s migration graph.
  • “Hot reload (WatchFiles/Uvicorn) is causing this.” Hot reload affects code loading, not which Postgres instance you connect to.

A Simple Decision Tree

  • Dev only, data can be wipedStrategy B (clean reset).
  • Keep data, treat DB as aligned to current repo nowStrategy A (stamp headupgrade head).
  • Just unblock quickly; data not importantStrategy C (stamp baseupgrade head).

Final Thoughts: Keep the problem outside the door

“Can’t locate revision …” errors are symptoms of environment consistency problems. Lock down your Docker context, ports, and volumes; add a fail‑fast preflight check; and gate autogeneration behind a flag. Next time you see:

Can't locate revision identified by '0997d75093b0'

Don’t delete files. Ask your DB who it is — then fix the mismatch with intent.


메타데이터
post_id
23c867f90ec0
slug
why-alembic-shouts-cant-locate-revision-the-hidden-trap-when-orbstack-and-docker-desktop-run-23c867f90ec0
url
https://medium.com/@dynamicy/why-alembic-shouts-cant-locate-revision-the-hidden-trap-when-orbstack-and-docker-desktop-run-23c867f90ec0
canonical_url
https://medium.com/@dynamicy/why-alembic-shouts-cant-locate-revision-the-hidden-trap-when-orbstack-and-docker-desktop-run-23c867f90ec0
author_url
https://medium.com/@dynamicy
status
ok
fetched_at
2026-06-22 12:55:45