{"record":{"id":"8ad40b0d95a02476","repo":"gastownhall/beads","slug":"failed-to-begin-ignored-tx-w","errorCode":null,"errorMessage":"failed to begin ignored tx: %w","messagePattern":"failed to begin ignored tx: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/transaction.go","lineNumber":397,"sourceCode":"// shipped flow diverges a pool session's branch from the regular tx's branch\n// (DoltStore.Checkout has no non-test callers), so this is defense in depth\n// for future Checkout callers and for multi-connection tests.\n//\n// Instead of an unconditional checkout it verifies the session is already on\n// the requested branch — the overwhelmingly common case — and sends the\n// caller to the fresh-dial fallback otherwise. Same round-trip count as the\n// checkout it replaces (one statement), so the borrow fast path stays free.\nfunc beginBorrowedTx(ctx context.Context, conn *sql.Conn, branch string) (*sql.Tx, error) {\n\tvar active string\n\tif err := conn.QueryRowContext(ctx, \"SELECT active_branch()\").Scan(&active); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read borrowed conn's active branch: %w\", err)\n\t}\n\tif active != branch {\n\t\treturn nil, fmt.Errorf(\"borrowed conn is on branch %q, want %q: refusing to switch a pooled session's branch\", active, branch)\n\t}\n\ttx, err := conn.BeginTx(ctx, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to begin ignored tx: %w\", err)\n\t}\n\treturn tx, nil\n}\n\n// beginTxOnConn checks a connection out to branch and begins a transaction on\n// it. Only the fallback path uses it: the fallback owns a dedicated\n// single-connection pool, so checking its session out is safe. Every Dolt SQL\n// session has its own active branch, so the explicit checkout is required on\n// a fresh dial.\nfunc beginTxOnConn(ctx context.Context, conn *sql.Conn, branch string) (*sql.Tx, error) {\n\tif _, err := conn.ExecContext(ctx, \"CALL DOLT_CHECKOUT(?)\", branch); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to checkout ignored tx branch %s: %w\", branch, err)\n\t}\n\ttx, err := conn.BeginTx(ctx, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to begin ignored tx: %w\", err)\n\t}\n\treturn tx, nil","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/transaction.go#L379-L415","documentation":"After verifying the borrowed session is on the right branch, beginBorrowedTx calls conn.BeginTx to start the ignored-tables transaction. This wraps a failure to BEGIN on that borrowed connection — the session died between the branch read and BEGIN, ctx was canceled, or the server rejected the transaction. The caller discards the connection and falls back to a fresh dial, so repeated occurrences point at server instability.","triggerScenarios":"Connection dropped between `SELECT active_branch()` and BEGIN; ctx deadline/cancellation hitting BeginTx; Dolt server refusing new transactions (shutdown, storage error); session killed server-side.","commonSituations":"Hosted-gateway load balancers killing sessions mid-use; server restarts; tight context deadlines; embedded Dolt under memory pressure.","solutions":["Retry — the borrow path falls back to a fresh dial automatically; if it surfaces repeatedly, investigate server stability","Check Dolt server logs at failure time for shutdown or storage errors","Widen ctx deadlines if cancellation is the cause","Keep ConnMaxLifetime below server idle/session timeouts so pooled sessions stay healthy"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if err := db.PingContext(ctx); err != nil { return fmt.Errorf(\"pool sessions unhealthy: %w\", err) }","typeGuard":null,"tryCatchPattern":"if err != nil && errors.Is(err, context.Canceled) {\n    return err // caller canceled: do not retry\n}\nif err != nil {\n    return freshDialFallback(ctx) // session died: safe to retry on a new connection\n}","preventionTips":["Keep pooled sessions healthy via ConnMaxLifetime below server session timeouts","Use realistic context deadlines for two-connection transaction setup","Investigate repeated occurrences — they usually indicate server restarts or LB session kills","Prefer the library's fresh-dial fallback over disabling the borrow path wholesale"],"tags":["go","sql","transaction","dolt"],"backgroundTag":"begin-transaction-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}