ory/hydra · error

backup.Finish failed

Error message

backup.Finish failed

What it means

Returned when backup.Finish() reports an error after the SQLite online-restore page copy loop completed. Finish releases backup resources; failure here usually signals an I/O error or that the step loop ended abnormally earlier, and the error is wrapped for diagnosis.

Source

Thrown at oryx/popx/migrator.go:121

			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())
	isSQLite := mb.c.Dialect.Name() == "sqlite3"
	isOnDiskSQLite = isSQLite && isOnDiskSQLite

	// For test SQLite databases, try to restore a pre-migrated template
	// using SQLite's online backup API. The restore streams pages directly into
	// the open connection, so mb.c stays valid throughout and any holders of

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Read the wrapped Finish error for the SQLite result code
  2. Ensure no other connections hold locks on the destination database during restore
  3. Verify the Step loop completed (more == false) before Finish — fix any early-break logic
  4. Retry the restore on an idle database

Example fix

// before
close other app connections then restore
// after
_ = db.Close() // ensure idle
db, _ = sql.Open("sqlite", dsn)
err := restoreSQLiteOnline(ctx, db, srcPath)
Defensive patterns

Strategy: retry

Validate before calling

// Ensure no other connections hold the destination DB
if err := db.PingContext(ctx); err != nil { return err }

Try / catch

if err := restoreSQLiteOnline(ctx, db, srcPath); err != nil {
  if strings.Contains(err.Error(), "backup.Finish failed") {
    // close other connections, then retry once
    return retryRestore(ctx, db, srcPath)
  }
  return err
}

Prevention

When it happens

Trigger: backup.Finish returns non-nil — typically when the backup was not fully completed (Step loop exited early) or the destination connection encountered an error finalizing the copy.

Common situations: Destination DB locked by another connection at finalization; earlier step errors leaving the backup in a bad state; driver-level failure committing the restored pages.

Related errors


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