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 ofView on GitHub (pinned to 4174065ffb)
Solutions
- Read the wrapped Finish error for the SQLite result code
- Ensure no other connections hold locks on the destination database during restore
- Verify the Step loop completed (more == false) before Finish — fix any early-break logic
- 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
- Run restores with exclusive access to the destination database
- Let the Step loop run to completion (more == false) before Finish
- Keep the restore connection alive until Finish returns
- Log the unwrapped SQLite result code for diagnostics
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
- driver %T does not support online restore
- NewRestore failed
- backup.Step failed
- failed to acquire sql.Conn for restore
- The DSN connection string looks like a SQLite connection, bu
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/ee7a9c2892549e3e.
Report an issue: GitHub.