gastownhall/beads · error
uow: pin connection: %w
Error message
uow: pin connection: %w
What it means
BeginTx acquires a dedicated connection from the sql.DB pool (p.db.Conn) to pin the unit of work's transaction to one session. This error wraps a pool acquisition failure as 'uow: pin connection: %w'.
Source
Thrown at internal/storage/uow/dolt_sql_provider.go:146
)
func (p *doltSQLProvider) NewUOW(ctx context.Context) (UnitOfWork, error) {
return NewUOW(ctx, p)
}
func (p *doltSQLProvider) Close(ctx context.Context) error {
if p.db == nil {
return nil
}
db := p.db
p.db = nil
return db.Close()
}
func (p *doltSQLProvider) BeginTx(ctx context.Context) (Tx, error) {
conn, err := p.db.Conn(ctx)
if err != nil {
return nil, fmt.Errorf("uow: pin connection: %w", err)
}
_, err = conn.ExecContext(ctx, "START TRANSACTION;")
if err != nil {
_ = conn.Close()
return nil, fmt.Errorf("uow: failed to start transaction: %w", err)
}
// Bind journal activation to the connection this unit of work is pinned to,
// AFTER START TRANSACTION so the seq allocation's UPDATE and the SELECT that
// must observe it are inside one transaction on one session. The scope is
// released when the connection is (doltServerTx.releaseConn / poisonConn),
// so an entry cannot outlive its transaction.
return &doltServerTx{
conn: conn,
clearJournalScope: issueops.ScopeEventsJournalTransaction(conn, p.eventsJournalEnabled.Load()),
}, nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Check the Dolt server is reachable (address/port in the DSN).
- Look for leaked transactions: every BeginTx connection must be released via the Tx's Commit/Rollback path (doltServerTx.releaseConn).
- Increase MaxOpenConns on the pool if the workload legitimately needs more concurrency.
- Retry with a fresh or longer-lived context if it was a transient timeout.
Example fix
// before
ctx := context.Background()
uow, err := provider.NewUOW(ctx) // hangs/fails when pool is busy
// after
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
uow, err := provider.NewUOW(ctx)
if err != nil {
return fmt.Errorf("begin unit of work: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// before opening units of work, verify the server answers
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := provider.Ping(ctx); err != nil {
return fmt.Errorf("dolt server unavailable: %w", err)
} Try / catch
tx, err := provider.BeginTx(ctx)
if err != nil {
var ctxErr = context.DeadlineExceeded
if errors.Is(err, ctxErr) || errors.Is(err, context.Canceled) {
return fmt.Errorf("timed out waiting for a pooled connection: %w", err)
}
return fmt.Errorf("cannot pin connection (server down or pool exhausted): %w", err)
} Prevention
- Always Commit/Rollback promptly; leaked Tx connections exhaust the pool.
- Set MaxOpenConns to fit the workload and the server's connection limit.
- Use a bounded context for BeginTx so waits fail fast with a clear cause.
- Alert on Dolt server restarts; pinned connections die with the server.
When it happens
Trigger: Calling BeginTx (directly or via NewUOW) when the pool cannot hand out a connection: pool exhausted (all connections busy and MaxOpenConns reached), context canceled/timed out while waiting, or the Dolt server is down.
Common situations: Long-running transactions leaking connections so the pool is exhausted; Dolt SQL server restarted or unreachable; a context deadline shorter than the pool's wait.
Related errors
- iter dependents: acquire conn: %w
- checkout active branch %q: %w
- failed to rebuild pool after migration: %w
- schema: pin connection: %w
- acquire connection for gc: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/53d69273367a96d9.
Report an issue: GitHub.