{"record":{"id":"045b94ff60d8e47b","repo":"gastownhall/beads","slug":"begin-write-tx-w","errorCode":null,"errorMessage":"begin write tx: %w","messagePattern":"begin write tx: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/store.go","lineNumber":1191,"sourceCode":"\t\t\t\ts.breaker.RecordFailure()\n\t\t\t\tif s.breaker.State() == circuitOpen {\n\t\t\t\t\tdoltMetrics.circuitTrips.Add(ctx, 1)\n\t\t\t\t\treturn backoff.Permanent(fmt.Errorf(\"%w (circuit breaker tripped)\", err))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err // pre-commit transient: retryable\n\t\t}\n\t\treturn backoff.Permanent(err)\n\t}, backoff.WithContext(bo, ctx))\n}\n\nfunc (s *DoltStore) withWriteTx(ctx context.Context, fn func(tx *sql.Tx) error) error {\n\tif s.closed.Load() {\n\t\treturn ErrStoreClosed\n\t}\n\ttx, err := s.db.BeginTx(ctx, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"begin write tx: %w\", err)\n\t}\n\tclearJournalScope := s.scopeEventsJournalTransaction(tx)\n\tdefer clearJournalScope()\n\tif err := fn(tx); err != nil {\n\t\treturn errors.Join(err, tx.Rollback())\n\t}\n\tif err := tx.Commit(); err != nil {\n\t\treturn wrapSQLCommitError(\"commit write tx\", err)\n\t}\n\treturn nil\n}\n\n// SetEventsJournalEnabled activates the journal for this store instance only.\nfunc (s *DoltStore) SetEventsJournalEnabled(enabled bool) {\n\ts.eventsJournalEnabled.Store(enabled)\n}\n\nfunc (s *DoltStore) scopeEventsJournalTransaction(tx *sql.Tx) func() {","sourceCodeStart":1173,"sourceCodeEnd":1209,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/store.go#L1173-L1209","documentation":"withWriteTx could not begin a SQL transaction on the store's shared connection pool (s.db). BeginTx fails when the pool is closed, the context is cancelled, all pooled connections are dead, or the Dolt server refuses new work. The store surfaces ErrStoreClosed separately, so this error specifically means an open store failed to start its write transaction.","triggerScenarios":"s.db.BeginTx(ctx, nil) returned an error — the Dolt server is unreachable, the pool's connections have timed out (client ReadTimeout of 10s or server read_timeout_millis), ctx was already cancelled, or the driver failed to dial a new pooled connection.","commonSituations":"Dolt sql-server stopped while the CLI/agent was mid-operation; long idle period let server-side timeouts reap connections; context deadline passed before the call; too many concurrent connections against a small server.","solutions":["Confirm the Dolt server is up and reachable; restart it if it died, and check the wrapped driver error for the concrete cause.","Check the context: ensure the caller passes a live context with an adequate deadline and does not cancel it early.","Retry — if used via withRetryTx, connection-class failures are retried with backoff; persistent errors indicate a real outage.","If connections keep dying on idle, reduce idle timeouts mismatch (client 10s ReadTimeout vs server read_timeout_millis) or keep traffic warm."],"exampleFix":"// before\ntx, err := store.db.BeginTx(ctx, nil)\n// after: fail fast with a clear cause\nif ctx.Err() != nil {\n    return fmt.Errorf(\"write tx not started, context done: %w\", ctx.Err())\n}\ntx, err := store.db.BeginTx(ctx, nil)\nif err != nil {\n    return fmt.Errorf(\"begin write tx: %w\", err)\n}","handlingStrategy":"retry","validationCode":"if err := ctx.Err(); err != nil {\n    return fmt.Errorf(\"context done before write: %w\", err)\n}\nif err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"dolt server unreachable before write: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := store.Update(ctx, op)\nif err != nil && strings.Contains(err.Error(), \"begin write tx\") {\n    // transient connection issue: retry with backoff, else surface\n    if errors.Is(err, driver.ErrBadConn) || isRetryable(err) {\n        time.Sleep(backoff)\n        err = store.Update(ctx, op)\n    }\n}","preventionTips":["Verify Dolt sql-server is running before long-running scripts that write.","Use live (non-expired) contexts for write operations; never reuse a cancelled parent ctx.","Watch for idle-connection reaping: align client ReadTimeout with the server's read_timeout_millis.","Wrap batch writes in withRetryTx so transient begin failures are retried automatically."],"tags":["dolt","database","transaction","connection"],"backgroundTag":"begin-transaction-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}