ory/hydra · error
neither normal (%s) nor legacy migration (%s) exist
Error message
neither normal (%s) nor legacy migration (%s) exist
What it means
During Down, if neither the migration's full-length version nor its legacy 14-char truncated version exists in schema_migration, the migrator cannot map the rollback to an applied migration and aborts. This prevents rolling back a migration that the tracking table says was never applied.
Source
Thrown at oryx/popx/migrator.go:383
if i >= attemptSteps {
break
}
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)View on GitHub (pinned to 4174065ffb)
Solutions
- Inspect schema_migration rows and compare with your migration files' versions
- If the migration was truly applied, manually INSERT the missing version row (full-length format) and re-run Down
- If it was never applied, verify you are on the right database/DSN and skip this migration
- Restore consistency from a backup if rows were deleted accidentally
Example fix
// before: row missing, Down aborts
// after: restore the tracked version then re-run Down
// INSERT INTO schema_migration (version) VALUES ('20221012101010'); Defensive patterns
Strategy: validation
Validate before calling
// verify every down-candidate version is tracked before calling Down
for _, v := range expectedVersions {
var ok bool
err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM schema_migration WHERE version=? OR version=?)", v, v[:min(14,len(v))]).Scan(&ok)
if err != nil || !ok { return fmt.Errorf("version %s not tracked", v) }
} Try / catch
if err := box.Down(ctx, 1); err != nil {
if strings.Contains(err.Error(), "neither normal nor legacy migration exist") {
// compare schema_migration rows with migration files, restore missing rows or correct DSN
}
return err
} Prevention
- Never hand-delete rows from schema_migration
- Use one migration tool consistently per database
- Back up schema_migration before restores or bulk edits
- Verify DSN points to the intended database
When it happens
Trigger: Calling Down when the migration count says rows exist but the specific candidate migration's version (and its legacy form) is missing from schema_migration — e.g. rows were manually deleted, or migrations were applied by a different tool/version that recorded different versions.
Common situations: Manual cleanup of schema_migration rows; running Down against a database migrated by another tool (goose, golang-migrate) with a different versioning scheme; truncated vs full timestamp mismatch after DB restore from partial backup.
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
- migration version %s does not exist
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/d56f91f85708464c.
Report an issue: GitHub.