ory/hydra · critical

problem inserting migration version %s. YOUR DATABASE MAY BE

Error message

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

What it means

When a migration is marked as no-transaction (shouldNotUseTransaction), the schema change runs outside a transaction; if the subsequent INSERT of the version row into schema_migration fails, the schema change has already been applied but not recorded, leaving the database in a partially migrated state. The library flags this explicitly as requiring manual intervention because it cannot roll back automatically.

Source

Thrown at oryx/popx/migrator.go:245

				continue
			}

			l.Info("Migration has not yet been applied, running migration.")

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

			noTx := mb.shouldNotUseTransaction(mi)
			if noTx {
				l.Info("NOT running migrations inside a transaction")
				if err := mi.Runner(mi, c); err != nil {
					return errors.WithStack(err)
				}

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

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

			l.WithField("autocommit", noTx).Infof("> %s applied successfully", mi.Name)

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Manually verify whether the migration's schema changes were applied (compare against the migration SQL)
  2. If the schema change exists, manually INSERT the missing version row: INSERT INTO schema_migration (version) VALUES ('<version>');
  3. If the schema change did not apply, fix the underlying cause (connection, locks, privileges) and re-run migrations
  4. Prefer transactional migrations for dialects that support transactional DDL to avoid this state

Example fix

// before: re-running migrations blindly
// $ app migrate up
// after: reconcile first, then re-run
// SELECT 1 FROM schema_migration WHERE version='20221012101010';
// INSERT INTO schema_migration (version) VALUES ('20221012101010'); -- if schema applied
Defensive patterns

Strategy: validation

Validate before calling

// before running no-tx migrations, verify tracking table writability
if err := db.RawQuery("SELECT 1 FROM schema_migration LIMIT 1").Exec(); err != nil {
    return fmt.Errorf("schema_migration unreadable, refusing no-tx migrate: %w", err)
}

Try / catch

if err := box.Up(ctx, -1); err != nil {
    if strings.Contains(err.Error(), "MANUAL INTERVENTION REQUIRED") {
        // compare applied schema against migration SQL, insert missing version row or re-run
    }
    return err
}

Prevention

When it happens

Trigger: Running an Up migration whose Runner is configured to run without a transaction (e.g. migration annotations like NO-TX, or dialects such as MySQL where DDL is non-transactional), and the INSERT INTO schema_migration fails after the migration body succeeded.

Common situations: Connection drop or timeout right after a long DDL migration; MySQL DDL implicit commits; DB lock on schema_migration table; disk full; insufficient INSERT privileges.

Related errors


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