Skip to content

Recover a Migration Directory After a Checksum Failure

Reproduce a changed migration file, restore its trusted bytes, and verify that Ptah preserves the deployed history and existing order.

Ptah helps you plan, review, and apply database migrations. Try in your browser

Ptah refuses a deployment because a migration no longer matches ptah.sum. The immediate question is which bytes changed and where the reviewed copy is. Rebuilding the checksum before answering that question would accept the change you are trying to investigate.

This first recovery article reproduces the failure with Ptah 0.13.0 and a disposable SQLite database. The example contains the original files, a trusted copy made before deployment, and the refusal and recovery output.

Our first migration creates an orders table with id and status. We hashed the migration directory, copied the sealed files into trusted-release/, applied them, and inserted one queued order.

We then changed status to state in the already-applied up file. The next verified deployment refused it:

Terminal window
ptah migrations up --db-url sqlite://shop.db --migrations-dir migrations --verify-sum
examples/measured/refused.txt
error: migration sum verification failed:
migration directory does not match ptah.sum:
changed: 0000000001_orders.up.sql

The command exited 2. This is a file-integrity failure before a new migration was deployed. It is different from a SQL statement failing halfway through execution, which the MySQL recovery article examines.

We compared the local file against the copy retained before deployment:

Terminal window
diff -u trusted-release/0000000001_orders.up.sql migrations/0000000001_orders.up.sql
examples/measured/difference.txt
--- trusted-release/0000000001_orders.up.sql 2026-10-19 02:15:39.018461428 +0200
+++ migrations/0000000001_orders.up.sql 2026-10-19 02:15:39.367136205 +0200
@@ -1 +1 @@
-CREATE TABLE orders (id integer PRIMARY KEY, status text NOT NULL DEFAULT 'queued');
+CREATE TABLE orders (id integer PRIMARY KEY, state text NOT NULL DEFAULT 'queued');

The difference explains the refusal: a column name changed in historical SQL. In this exercise we know that the original artifact is correct. In a real incident, establish the reviewed release or immutable artifact first. A checksum establishes consistency with its manifest; it does not by itself authenticate who published the manifest.

Do not edit the migration history table to make the discrepancy disappear. The database already has the original table. If the application now needs a renamed column, that requires a new reviewed migration and compatibility checks, rather than rewriting the description of an old deployment.

We restored the changed file from the retained release:

Terminal window
cp trusted-release/0000000001_orders.up.sql migrations/0000000001_orders.up.sql
ptah migrations validate --dir migrations
examples/measured/verify.txt
OK: migrations directory matches ptah.sum

No new checksum was needed because the original file again matched the original manifest. Retrying the deployment reported version 1 and zero pending migrations. A separate client still read the existing order:

examples/measured/rows.txt
[(1, 'queued')]

The recorded recovery preserved the database and restored the deployment artifact. It did not replay the CREATE statement, rename the live column, or delete migration history.

For this incident, the changed file was accidental and the trusted artifact was available. Other checksum failures need their own diagnosis: an extra file, a missing file, or a changed manifest is a different difference to explain. Keep the failed directory for inspection and identify the expected release before replacing anything.

The integrity guide describes the native checks. If bytes match but deployment waits on the database, continue with Find the Transaction Blocking Your Migration.

If these checks do not explain your failure, open an issue for a reproducible defect or start a discussion for help choosing a recovery path. Include the Ptah and database versions, the command, a minimal synthetic fixture, and redacted output. Leave credentials and private production data out of the report.

Put Ptah to work

Example files