Files
asmhatreandClaude Sonnet 5 67e1b2d8a9 db-migrations-flyway-liquibase: fix dead Redgate/Liquibase doc links and back the lock-defaults claim with a real transcript
Several documentation.red-gate.com and liquibase.com URLs added in the previous commit had
since moved (Redgate restructured its docs under /flyway/reference/, Liquibase Pro pricing
moved to /pricing); this repoints them at the current, verified-200 pages. Also captures
docs/output/16-liquibase-lock-defaults-javap.txt, the trimmed javap output backing chapter
11's claim about Liquibase's default lock-poll and lock-wait settings, which chapter 11
previously asserted without a committed artifact to back it.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q6XdRjtsp4862EM44T7i9a
2026-09-15 07:31:49 +00:00

4.8 KiB

4. Out-of-order migrations

← 3. Checksum validation · Index · Next: 5. Repeatable migrations →

Two branches, both adding "the next migration": one ships V3 and merges quickly, the other's V2 sits in a slow-to-review pull request and lands afterward. By the time V2 merges, every environment that deployed the first branch already has V3 applied. What happens when V2 finally shows up?

FlywayOutOfOrderTest reproduces exactly this: V1 and V3 apply on a first startup, then V2__add_note_length_check.sql is dropped in afterward, and a second startup runs against the same database.

The common assumption — that Flyway just quietly skips the late-arriving lower version and carries on — is wrong. The whole application fails to start:

context failed to start: FlywayValidateException: Validate failed: Migrations have failed validation
Detected resolved migration not applied to database: 2.
To ignore this migration, set -ignoreMigrationPatterns='*:ignored'. To allow executing this migration, set -outOfOrder=true.

(from docs/output/03-flyway-out-of-order.txt; this test was originally written expecting the silent-skip behaviour, and the real run corrected it)

Validation runs before migration, and by default (spring.flyway.out-of-order=false) a resolved migration with a version lower than the highest already-applied one is treated as a validation failure, not a no-op. Nothing gets applied and the context never comes up.

history: V1 ✓, V3 ✓ V1 V3 V2? out-of-order=false (default) whole startup fails

same history, out-of-order=true V2 runs, slotted in after V3 history keeps its real apply order: V1, V3, V2 — not renumbered

Setting spring.flyway.out-of-order=true is the fix the error message itself names, and a third startup in the same test confirms what it actually does: V2 runs, and the history table keeps it in real application order — rank 3, version 2, sitting after rank 2's version 3 — Flyway does not retroactively renumber or reorder anything:

installed_rank | version | description                               | success
---------------+---------+-------------------------------------------+--------
-1             | NULL    | << Flyway Schema History table created >> | true
1              | 1       | init                                      | true
2              | 3       | add note index                            | true
3              | 2       | add note length check                     | true

(from the same transcript)

Going deeper

  • outOfOrder is a blunt, global switch — turning it on doesn't just allow the one late migration you're expecting, it allows any lower-numbered migration to slot in from then on. Flyway's own docs call this out as reducing reproducibility, and docs/output/03-flyway-out-of-order.txt's third-startup log line says so verbatim: outOfOrder mode is active. Migration of schema may not be reproducible.
  • ignoreMigrationPatterns (rel="nofollow") — the error message's other suggested fix, for permanently ignoring a specific migration instead of relaxing ordering globally.
  • A team that hits this regularly is usually missing a CI check that fails a PR when its migration's version number is lower than what's already merged to main — cheaper than relying on outOfOrder at all.