ory/hydra · error
migration version %s does not exist
Error message
migration version %s does not exist
What it means
During Down, when a migration version is shorter than or equal to 14 characters (so no legacy variant applies) and its row is not present in schema_migration, the migrator aborts with this error. It refuses to roll back a migration that is not recorded as applied.
Source
Thrown at oryx/popx/migrator.go:386
l := mb.l.WithField("version", mi.Version).WithField("migration_name", mi.Name).WithField("migration_file", mi.Path)
l.Debugf("handling migration %s", mi.Name)
exists, err := c.Where("version = ?", mi.Version).Exists(mtn)
if err != nil {
return errors.Wrapf(err, "problem checking for migration version %s", mi.Version)
}
if !exists && len(mi.Version) > 14 {
legacyVersion := mi.Version[:14]
legacyVersionExists, err := c.Where("version = ?", legacyVersion).Exists(mtn)
if err != nil {
return errors.Wrapf(err, "problem checking for legacy migration version %s", legacyVersion)
}
if !legacyVersionExists {
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 {View on GitHub (pinned to 4174065ffb)
Solutions
- Compare the migrations listed in your schema_migration table with your migration files
- Re-insert the missing version row if the migration was actually applied, then re-run Down
- Confirm the correct database/DSN; the row may exist in another database
- Skip/patch the migration set so Down only targets recorded versions
Example fix
// before
// DELETE FROM schema_migration WHERE version='20221012'; -- accidental
// after: re-insert then Down
// INSERT INTO schema_migration (version) VALUES ('20221012'); Defensive patterns
Strategy: validation
Validate before calling
// confirm the exact version exists in the tracking table before Down
var ok bool
if err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM schema_migration WHERE version=?)", version).Scan(&ok); err != nil || !ok {
return fmt.Errorf("version %s not recorded; refusing rollback", version)
} Try / catch
if err := box.Down(ctx, 1); err != nil {
if strings.Contains(err.Error(), "does not exist") {
// reconcile schema_migration with migration files before retrying
}
return err
} Prevention
- Keep schema_migration rows in sync with applied migrations
- Avoid mixing migration tools on the same database
- Snapshot the tracking table before maintenance
When it happens
Trigger: Calling Down for a candidate migration whose version row is absent from schema_migration: count-based selection picked it because other rows exist, but this specific version was never recorded or was deleted.
Common situations: Manually deleted schema_migration rows; database restored from a partial backup; running Down on a database migrated with a different tool; legacy-version rows present but count-based selection referencing a short version migration not in the table.
Related errors
- problem inserting migration version %s
- problem inserting migration version %s. YOUR DATABASE MAY BE
- migration down: unable count existing migration
- problem checking for legacy migration version %s
- neither normal (%s) nor legacy migration (%s) exist
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/b300d5530fb311ed.
Report an issue: GitHub.