ory/hydra · critical

problem deleting migration version %s. YOUR DATABASE MAY BE

Error message

problem deleting migration version %s. YOUR DATABASE MAY BE IN AN INCONSISTENT STATE! MANUAL INTERVENTION REQUIRED!

What it means

When a Down migration runs outside a transaction (no-transaction migration), the rollback schema change executes first; if the subsequent DELETE of the version row from schema_migration fails, the schema has been rolled back but the tracking row remains, leaving the database in an inconsistent state that requires manual intervention. The library cannot undo the applied rollback automatically.

Source

Thrown at oryx/popx/migrator.go:401

					return errors.Errorf("neither normal (%s) nor legacy migration (%s) exist", mi.Version, legacyVersion)
				}
			} else if !exists {
				return errors.Errorf("migration version %s does not exist", mi.Version)
			}

			if err := mi.Valid(); err != nil {
				return errors.WithStack(err)
			}

			if mb.shouldNotUseTransaction(mi) {
				err := mi.Runner(mi, c)
				if err != nil {
					return errors.WithStack(err)
				}

				// #nosec G201 - mtn is a system-wide const
				if err := c.RawQuery(fmt.Sprintf("DELETE FROM %s WHERE version = ?", mtn), mi.Version).Exec(); err != nil {
					return errors.Wrapf(err, "problem deleting migration version %s. YOUR DATABASE MAY BE IN AN INCONSISTENT STATE! MANUAL INTERVENTION REQUIRED!", mi.Version)
				}
			} else {
				if err := mb.isolatedTransaction(ctx, "down", func(conn *pop.Connection) error {
					err := mi.Runner(mi, conn)
					if err != nil {
						return errors.WithStack(err)
					}

					// #nosec G201 - mtn is a system-wide const
					if err := conn.RawQuery(fmt.Sprintf("DELETE FROM %s WHERE version = ?", mtn), mi.Version).Exec(); err != nil {
						return errors.Wrapf(err, "problem deleting migration version %s", mi.Version)
					}

					return nil
				}); err != nil {
					return errors.WithStack(err)
				}
			}

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Verify the migration's rollback actually took effect in the schema
  2. If the schema was rolled back, manually DELETE the version row: DELETE FROM schema_migration WHERE version='<version>';
  3. If the rollback did not apply, fix the cause and manually remove or keep the row to match reality, then re-run Down
  4. Use transactional migrations where the dialect supports transactional DDL

Example fix

// after a failed auto-delete, reconcile manually
// SELECT 1 FROM schema_migration WHERE version='20221012101010';
// DELETE FROM schema_migration WHERE version='20221012101010'; -- if rollback applied
Defensive patterns

Strategy: try-catch

Validate before calling

// check DELETE privileges on the tracking table before no-tx rollbacks
if err := db.RawQuery("SELECT 1 FROM schema_migration LIMIT 1").Exec(); err != nil {
    return fmt.Errorf("cannot read schema_migration; aborting no-tx Down: %w", err)
}

Try / catch

if err := box.Down(ctx, 1); err != nil {
    if strings.Contains(err.Error(), "MANUAL INTERVENTION REQUIRED") {
        // verify whether the schema rollback applied; DELETE the version row manually if it did
    }
    return err
}

Prevention

When it happens

Trigger: Calling Down for a no-transaction migration where the migration body succeeds but the DELETE FROM schema_migration fails (connection drop, lock, permissions).

Common situations: MySQL-style non-transactional DDL rollbacks followed by connection loss; concurrent lock on schema_migration; DB user lacking DELETE privileges; disk-full incidents.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/f6a20b1afb0ca9f6. Report an issue: GitHub.