ory/hydra · error
failed to acquire sql.Conn for restore
Error message
failed to acquire sql.Conn for restore
What it means
restoreSQLiteOnline performs an online SQLite backup by first acquiring a dedicated *sql.Conn from the pool. If db.Conn(ctx) fails (context canceled/expired or pool acquisition failure), the error is wrapped as 'failed to acquire sql.Conn for restore'.
Source
Thrown at oryx/popx/migrator.go:91
dir := mb.sqliteTemplateCacheDir
if dir == "" {
dir = os.TempDir()
}
return filepath.Join(dir, "ory-popx-sqlite-template-"+hex.EncodeToString(h.Sum(nil))+".sqlite")
}
// restoreSQLiteOnline streams the contents of srcPath into the database
// represented by db using SQLite's online backup API. The destination
// connection stays open throughout, so the *sql.DB and any pop.Connection
// holding it remain valid.
//
// pop wraps the modernc.org/sqlite driver with otelsql for tracing; we
// unwrap via the otelsql Raw() accessor before reaching the driver-specific
// NewRestore method on the underlying *sqlite.conn.
func restoreSQLiteOnline(ctx context.Context, db *sql.DB, srcPath string) error {
conn, err := db.Conn(ctx)
if err != nil {
return errors.Wrap(err, "failed to acquire sql.Conn for restore")
}
defer func() { _ = conn.Close() }()
return conn.Raw(func(driverConn any) error {
if w, ok := driverConn.(interface{ Raw() driver.Conn }); ok {
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")
}View on GitHub (pinned to 4174065ffb)
Solutions
- Check the wrapped cause: if context deadline, increase the timeout or use context.Background() for migrations
- Ensure the *sql.DB is open and not closed before UpTo runs
- Avoid holding all pool connections concurrently with the restore
- Retry the migration after freeing connections
Example fix
// before err := mb.UpTo(ctx, -1) // ctx already near deadline // after restoreCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() err := mb.UpTo(restoreCtx, -1)
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure context is healthy and DB is open before migrating
if err := ctx.Err(); err != nil { return err }
if err := db.PingContext(ctx); err != nil { return err } Try / catch
if err := mb.UpTo(ctx, -1); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
// retry with a fresh, longer-lived context
}
if strings.Contains(err.Error(), "failed to acquire sql.Conn") {
// reduce concurrent pool usage, retry
}
return err
} Prevention
- Use a dedicated context (not request-scoped) for migrations
- Avoid saturating the connection pool while migrations run
- Ping the DB and check ctx.Err() before starting migrations
- Don't close the *sql.DB before UpTo completes
When it happens
Trigger: Calling UpTo on a SQLite database whose connection pool cannot hand out a connection: context deadline exceeded, context canceled, or all pooled connections busy / pool closed.
Common situations: Parent request context timing out during a long restore; database already closed; connection pool exhausted by concurrent operations; restore path invoked during app shutdown.
Related errors
- The DSN connection string looks like a SQLite connection, bu
- unsupported dialect
- invalid DSN: missing scheme separator
- invalid DSN: empty scheme
- database error on committing or rolling back transaction: %w
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/ebb5f959588f88cf.
Report an issue: GitHub.