Skip to content

Migrator: 'migrate latest' output is confusing when DB tracks a version with no matching file (shared dev DB / peer in-flight) #2780

@bpamiri

Description

@bpamiri

Summary

In a shared development database scenario (multiple developers sharing a single dev DB), the migration tracking table can record a version that has no corresponding migration file in the current checkout — because a peer applied a migration but their file isn't yet in your branch.

When this happens, `wheels migrate latest` produces output that looks like a successful operation but is actually a no-op refusal:

```
$ wheels migrate latest
Running migration: latest...
Migrating from 20260521120100 down to 20260521111543.
$
```

Then `wheels migrate up` says:

```
No pending migrations. Database is at version 20260521120100.
```

Even though `wheels migrate info` shows the new local migration as `[ ]` pending. The trio of outputs contradicts itself.

Root cause

The CLI sorts migrations by timestamp. When the DB's recorded "current version" timestamp is higher than the highest local migration file, `migrate latest` interprets the situation as "the DB is ahead of where you want it" and tries to roll DOWN to your latest local version. But because the file for the higher version doesn't exist, there's no `down()` to call, so nothing happens.

Suggested fixes

  1. Detect and warn: when the DB tracking table contains a version that has no matching file, print a clear warning:
    ```
    Warning: database tracks migration version 20260521120100 but no matching file
    exists in app/migrator/migrations/. This usually means a peer applied a
    migration whose file isn't yet in your branch. Your new migrations need
    timestamps newer than 20260521120100 to apply.
    ```
  2. Better directional output: "Migrating from X down to Y" should not appear when the user ran `migrate latest` (a forward command). At minimum print "Nothing to do — your latest local migration (Y) is older than the database's current version (X). Either pull peer migrations or renumber your files."
  3. Doc fix: add a section to migrator docs explaining the shared-DB pattern and how to choose safe timestamps.

Repro

  1. Insert a fake high-version row into the migration tracking table.
  2. Create a new migration file with an earlier timestamp.
  3. Run `wheels migrate latest` — observe confusing output and no-op behavior.

Repo / version

  • CLI: `wheels 4.0.1`
  • Wheels Core: `4.0.0-SNAPSHOT+1779`

Where found

Surfaced while executing DataPAI portal Phase 0 against Titan's shared development MSSQL database.

🤖 Found while executing a Claude-Code-driven implementation plan

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions