ory/hydra · error

problem deleting migration version %s

Error message

problem deleting migration version %s

What it means

During a transactional Down migration, the rollback and the DELETE of the version row share one transaction; if the DELETE fails the whole transaction (including the rollback) is undone and this error is returned. The database remains consistent — the migration was simply not reverted.

Source

Thrown at oryx/popx/migrator.go:412

				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)
				}
			}

			l.Infof("%s applied successfully", mi.Name)
			reverted++
			remainingSteps--
		}
		return nil
	}))
}

func (mb *MigrationBox) createTransactionalMigrationTable(ctx context.Context, c *pop.Connection, l *logrusx.Logger) error {
	mtn := sanitizedMigrationTableName(c)

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Inspect the wrapped cause for the underlying SQL error and fix it
  2. Confirm schema_migration exists and the DB user has DELETE privileges
  3. Re-run Down after the fix; transactional semantics guarantee no partial state
Defensive patterns

Strategy: try-catch

Validate before calling

var n int
if err := db.QueryRow("SELECT COUNT(*) FROM schema_migration").Scan(&n); err != nil {
    return fmt.Errorf("tracking table unreadable before Down: %w", err)
}

Try / catch

if err := box.Down(ctx, 1); err != nil {
    if isTransient(err) {
        time.Sleep(time.Second)
        return box.Down(ctx, 1) // transactional: safe to retry, state is consistent
    }
    return err
}

Prevention

When it happens

Trigger: Calling Down for a transactional migration where DELETE FROM schema_migration fails inside the isolated transaction: unique/foreign-key issues, table missing, privileges, or connection loss mid-transaction.

Common situations: schema_migration dropped or locked by another process; revoked DELETE privileges; transient connection failures during long rollbacks.

Related errors


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