ory/hydra · error

backup.Step failed

Error message

backup.Step failed

What it means

Returned during SQLite online restore when backup.Step(-1), which copies all remaining pages from the source database, fails. The underlying error comes from the SQLite backup API — source database locked, I/O error, or corrupt source — and Finish is called before returning.

Source

Thrown at oryx/popx/migrator.go:115

			driverConn = w.Raw()
		}
		restorer, ok := driverConn.(interface {
			NewRestore(srcUri string) (*moderncsqlite.Backup, error)
		})
		if !ok {
			return errors.Errorf("driver %T does not support online restore", driverConn)
		}
		// See: https://sqlite.org/backup.html .
		backup, err := restorer.NewRestore(srcPath)
		if err != nil {
			return errors.Wrap(err, "NewRestore failed")
		}
		// Step(-1) copies all remaining pages in one call.
		for {
			more, stepErr := backup.Step(-1)
			if stepErr != nil {
				_ = backup.Finish()
				return errors.Wrap(stepErr, "backup.Step failed")
			}
			if !more {
				break
			}
		}
		return errors.Wrap(backup.Finish(), "backup.Finish failed")
	})
}

// UpTo runs up to step "up" migrations and applies them to the database.
// If step <= 0 all pending migrations are run.
func (mb *MigrationBox) UpTo(ctx context.Context, step int) (applied int, err error) {
	ctx, span := startSpan(ctx, MigrationUpOpName, trace.WithAttributes(attribute.Int("step", step)))
	defer otelx.End(span, &err)

	c := mb.c.WithContext(ctx)

	newDbFileName, isOnDiskSQLite := sqliteFilePath(mb.c.URL())

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Ensure no concurrent writers touch the source or destination during the backup
  2. Check disk space on the destination volume
  3. Inspect the wrapped stepErr for the specific SQLite result code
  4. Retry the restore once the database is quiescent

Example fix

// before
backup running while app writes to DB
// after
mu.Lock()
err := restoreSQLiteOnline(ctx, db, srcPath)
mu.Unlock()
Defensive patterns

Strategy: retry

Validate before calling

// Ensure destination is idle before restore
if err := db.PingContext(ctx); err != nil { return err }
// Ensure sufficient disk space
if free, _ := diskFree("."); free < minRequiredBytes { return errors.New("insufficient disk space") }

Try / catch

for attempt := 0; attempt < 3; attempt++ {
  err := restoreSQLiteOnline(ctx, db, srcPath)
  if err == nil || !strings.Contains(err.Error(), "backup.Step failed") {
    return err
  }
  time.Sleep(time.Duration(attempt+1) * time.Second)
}
return errors.New("restore failed after retries")

Prevention

When it happens

Trigger: The SQLite backup process fails mid-copy — e.g. the source or destination database is modified/locked during the backup, IO errors occur, or the source file changes underneath the backup handle.

Common situations: Concurrent writes to the source DB during restore; disk full while copying pages; source file truncated or corrupted mid-read; another process holding an exclusive lock.

Related errors


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