gastownhall/beads · error
uow: failed to start transaction: %w
Error message
uow: failed to start transaction: %w
What it means
After pinning a connection, BeginTx executes 'START TRANSACTION;' on it. If that statement fails, the connection is closed and this error wraps the cause as 'uow: failed to start transaction: %w'.
Source
Thrown at internal/storage/uow/dolt_sql_provider.go:152
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
}
// selectProbeDatabase lets schema's pre-lock convergence probe reach the
// database on a session that is not yet on one. openAndInitSchema pins its
// schema-init pool with an EMPTY DSN database, so without this the probe reads
// NULL from DATABASE(), declines, and every invocation queues on the
// server-wide migration lock it exists to skip.View on GitHub (pinned to 71377f2769)
Solutions
- Retry the unit of work — pool connections are refreshed automatically after a dropped session.
- Increase the context timeout if START TRANSACTION is racing the deadline.
- Check Dolt server logs for session kills or restarts at the failure time.
- Verify no proxy/idle timeout (defaultProxyIdleTimeout) is reaping connections mid-open.
Example fix
// before
uow, err := provider.NewUOW(ctx) // one short ctx reused everywhere
// after
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
uow, err := provider.NewUOW(ctx)
if err != nil {
var retryable bool // serialization errors surface similarly
_ = retryable
return err
} Defensive patterns
Strategy: retry
Validate before calling
// health-check the server before starting transactions
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("dolt server not ready for transactions: %w", err)
} Try / catch
tx, err := provider.BeginTx(ctx)
if err != nil {
if strings.Contains(err.Error(), "failed to start transaction") {
// connection likely dropped between Conn() and START TRANSACTION — safe to retry once
return retryOnce(ctx, provider.BeginTx)
}
return err
} Prevention
- Keep contexts generous relative to network latency to the server.
- Raise proxy idle timeouts if the server reaps idle sessions mid-open.
- Treat any server restart as invalidating in-flight transactions; retry from scratch.
- Monitor server logs for 'server has gone away' style kills.
When it happens
Trigger: conn.ExecContext(ctx, "START TRANSACTION;") returns an error: the server dropped the connection, the context was canceled mid-statement, or the session is in a state that refuses a new transaction (e.g. an implicit transaction already open on that pinned session).
Common situations: Dolt server restart or idle timeout killing the pinned connection between Conn() and START TRANSACTION; network interruption; ctx deadline expiring exactly during transaction start.
Related errors
- ErrTransaction
- open unit of work: %w
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to begin transaction: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/0e4f6615c6961ea6.
Report an issue: GitHub.