ory/hydra · error

problem inserting migration version %s

Error message

problem inserting migration version %s

What it means

During UpTo, when a migration was already applied under the legacy 14-char version format, the migrator inserts a new full-length version row inside an 'init-migrate' transaction so the migration is tracked under the current scheme. This error wraps a failure of that INSERT into the schema_migration table. It usually means the migration tracking table is unreachable, locked, or violates constraints.

Source

Thrown at oryx/popx/migrator.go:223

			if slices.Contains(appliedMigrations, mi.Version) {
				l.Debug("Migration has already been applied, skipping.")
				continue
			}

			if slices.Contains(appliedMigrations, legacyVersion) {
				l.WithField("legacy_version", legacyVersion).WithField("migration_table", mtn).Debug("Migration has already been applied in a legacy migration run. Updating version in migration table.")
				if err := mb.isolatedTransaction(ctx, "init-migrate", func(conn *pop.Connection) error {
					// We do not want to remove the legacy migration version or subsequent migrations might be applied twice.
					//
					// Do not activate the following - it is just for reference.
					//
					// if _, err := tx.Store.Exec(fmt.Sprintf("DELETE FROM %s WHERE version = ?", mtn), legacyVersion); err != nil {
					//	return errors.Wrapf(err, "problem removing legacy version %s", mi.Version)
					// }

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

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Check the schema_migration table exists and the DB user has INSERT privileges on it
  2. Inspect the wrapped cause for the real SQL error (e.g. unique violation, table missing) and fix accordingly
  3. Re-run migrations; the operation is idempotent because the legacy row is intentionally kept
  4. If a duplicate row is the cause, manually remove the conflicting row before re-running

Example fix

// before (diagnostic)
// SELECT * FROM schema_migration WHERE version LIKE '20221012%';
// after: remove conflicting duplicate then re-run
// DELETE FROM schema_migration WHERE version = '20221012101010';
Defensive patterns

Strategy: try-catch

Validate before calling

var n int
if err := db.QueryRow("SELECT COUNT(*) FROM schema_migration").Scan(&n); err != nil {
    // table missing/unreadable — run migrations init first
}

Try / catch

if err := box.Up(ctx, -1); err != nil {
    if strings.Contains(err.Error(), "problem inserting migration version") {
        // inspect wrapped cause, verify schema_migration table and privileges, reconcile, retry
    }
    return err
}

Prevention

When it happens

Trigger: Running migrations Up while the schema_migration table contains the legacy truncated (14-char) version of a migration, and the INSERT of the full-length version fails (table missing, dropped, locked, unique index violation, permissions, connection dropped).

Common situations: Databases upgraded from older versions of the library that stored truncated timestamps; a manually emptied or renamed schema_migration table; DB user lacking INSERT privileges; connection dropped mid-migration.

Related errors


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