gastownhall/beads · error
acquire connection for merge: %w
Error message
acquire connection for merge: %w
What it means
MergeWithStrategy needs a dedicated connection pinned for the Dolt merge session. This error wraps a failure from s.db.Conn(ctx) when acquiring that connection. Pool exhaustion is the notable trigger here — the surrounding code even documents that recomputeBlockedAfterPull needs its own connection and the pool may be MaxOpenConns:1.
Source
Thrown at internal/storage/dolt/store.go:4917
ctx, span := doltTracer.Start(ctx, "dolt.merge_with_strategy",
trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(append(s.doltSpanAttrs(),
attribute.String("dolt.merge_branch", branch),
attribute.String("dolt.merge_strategy", strategy),
)...),
)
defer func() { endSpan(span, retErr) }()
preHead := ""
if !s.readOnly {
if h, err := s.GetCurrentCommit(ctx); err == nil {
preHead = h
}
}
conn, err := s.db.Conn(ctx)
if err != nil {
return nil, fmt.Errorf("acquire connection for merge: %w", err)
}
conflicts, err = versioncontrolops.MergeWithStrategy(ctx, conn, branch, s.commitAuthorString(), strategy)
// Release the pinned connection before the recompute: s.db's pool can be
// configured with a single connection (setupTestStore's MaxOpenConns: 1
// mirrors constrained production configs), and recomputeBlockedAfterPull
// acquires its own connection — held past this point, conn would starve
// it of the only one available.
closeErr := conn.Close()
if len(conflicts) > 0 {
span.SetAttributes(attribute.Int("dolt.conflicts", len(conflicts)))
}
if err != nil {
return conflicts, err
}
if closeErr != nil {
return conflicts, fmt.Errorf("release merge connection: %w", closeErr)
}
if !s.readOnly {View on GitHub (pinned to 71377f2769)
Solutions
- Close/commit all other connections, txs, and rows before merging.
- Follow the codebase's own pattern: release the conn (conn.Close()) before running recomputeBlockedAfterPull.
- Increase MaxOpenConns so merge and recompute can each hold a connection.
- Check ctx deadlines if the pool wait is being cancelled.
- Confirm the Dolt server is healthy; retry to evict stale pooled connections.
Example fix
// before
conn, err := s.db.Conn(ctx)
if err != nil { return nil, fmt.Errorf("acquire connection for merge: %w", err) }
conflicts, err = versioncontrolops.MergeWithStrategy(ctx, conn, ...)
// recompute runs while conn still held -> starvation
// after
conflicts, err := func() ([]Conflict, error) {
conn, err := s.db.Conn(ctx)
if err != nil { return nil, fmt.Errorf("acquire connection for merge: %w", err) }
defer conn.Close()
return versioncontrolops.MergeWithStrategy(ctx, conn, ...)
}()
if err != nil { return conflicts, err }
// now recompute can acquire its own connection Defensive patterns
Strategy: validation
Validate before calling
stats := db.Stats()
if stats.MaxOpenConnections > 0 && stats.InUse >= stats.MaxOpenConnections {
return errors.New("cannot merge: connection pool exhausted; release pinned connections first")
}
if err := ctx.Err(); err != nil { return err } Try / catch
conn, err := s.db.Conn(ctx)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return fmt.Errorf("merge starved waiting for connection (pool=%d in use)", db.Stats().InUse)
}
return fmt.Errorf("acquire connection for merge: %w", err)
} Prevention
- Close the merge connection before recomputeBlockedAfterPull (as the codebase comment mandates)
- Avoid MaxOpenConns:1 with multi-connection workflows; test configs should mirror production sizing
- Always defer conn.Close() right after a successful acquire
- Alert on pool wait metrics to catch starvation early
When it happens
Trigger: Calling the store's strategy merge (bd vc merge --strategy) when s.db.Conn(ctx) fails: another operation (often a still-pinned conn or an in-flight recompute) holds the sole connection, or ctx expires while queued for the pool.
Common situations: Test stores configured with MaxOpenConns:1 mirroring constrained production; concurrent merge and recompute operations; Dolt server unresponsive so pooled conns are dead.
Related errors
- iter dependents: acquire conn: %w
- checkout active branch %q: %w
- failed to rebuild pool after migration: %w
- acquire connection for gc: %w
- acquire connection for remote-ref prune: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4f397a3b649d5f0b.
Report an issue: GitHub.