{"record":{"id":"53d69273367a96d9","repo":"gastownhall/beads","slug":"uow-pin-connection-w","errorCode":null,"errorMessage":"uow: pin connection: %w","messagePattern":"uow: pin connection: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/uow/dolt_sql_provider.go","lineNumber":146,"sourceCode":")\n\nfunc (p *doltSQLProvider) NewUOW(ctx context.Context) (UnitOfWork, error) {\n\treturn NewUOW(ctx, p)\n}\n\nfunc (p *doltSQLProvider) Close(ctx context.Context) error {\n\tif p.db == nil {\n\t\treturn nil\n\t}\n\tdb := p.db\n\tp.db = nil\n\treturn db.Close()\n}\n\nfunc (p *doltSQLProvider) BeginTx(ctx context.Context) (Tx, error) {\n\tconn, err := p.db.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"uow: pin connection: %w\", err)\n\t}\n\n\t_, err = conn.ExecContext(ctx, \"START TRANSACTION;\")\n\tif err != nil {\n\t\t_ = conn.Close()\n\t\treturn nil, fmt.Errorf(\"uow: failed to start transaction: %w\", err)\n\t}\n\n\t// Bind journal activation to the connection this unit of work is pinned to,\n\t// AFTER START TRANSACTION so the seq allocation's UPDATE and the SELECT that\n\t// must observe it are inside one transaction on one session. The scope is\n\t// released when the connection is (doltServerTx.releaseConn / poisonConn),\n\t// so an entry cannot outlive its transaction.\n\treturn &doltServerTx{\n\t\tconn:              conn,\n\t\tclearJournalScope: issueops.ScopeEventsJournalTransaction(conn, p.eventsJournalEnabled.Load()),\n\t}, nil\n}","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/uow/dolt_sql_provider.go#L128-L164","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nctx := context.Background()\nuow, err := provider.NewUOW(ctx) // hangs/fails when pool is busy\n\n// after\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\ndefer cancel()\nuow, err := provider.NewUOW(ctx)\nif err != nil {\n    return fmt.Errorf(\"begin unit of work: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// before opening units of work, verify the server answers\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\nif err := provider.Ping(ctx); err != nil {\n    return fmt.Errorf(\"dolt server unavailable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"tx, err := provider.BeginTx(ctx)\nif err != nil {\n    var ctxErr = context.DeadlineExceeded\n    if errors.Is(err, ctxErr) || errors.Is(err, context.Canceled) {\n        return fmt.Errorf(\"timed out waiting for a pooled connection: %w\", err)\n    }\n    return fmt.Errorf(\"cannot pin connection (server down or pool exhausted): %w\", err)\n}","preventionTips":["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."],"tags":["database","connection-pool","context-timeout"],"backgroundTag":"connection-pool-exhausted","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}