gastownhall/beads · error
failed to begin regular tx: %w
Error message
failed to begin regular tx: %w
What it means
After reading the active branch, runDoltTransaction begins the regular SQL transaction with conn.BeginTx(ctx, nil). This error wraps a failure to start that transaction on the pinned connection — the session died between the branch read and BEGIN, the context was canceled, or the server rejected the transaction start (e.g. server shutting down, lock-table unavailable).
Source
Thrown at internal/storage/dolt/transaction.go:196
doltMetrics.poolWaitCount.Add(ctx, statsAfter.WaitCount-statsBefore.WaitCount)
waitMs := float64(statsAfter.WaitDuration-statsBefore.WaitDuration) / float64(time.Millisecond)
doltMetrics.poolWaitMs.Record(ctx, waitMs)
}
}
if err != nil {
return fmt.Errorf("failed to acquire connection: %w", err)
}
defer conn.Close()
var currentBranch string
if err := conn.QueryRowContext(ctx, "SELECT active_branch()").Scan(¤tBranch); err != nil {
return fmt.Errorf("failed to read active branch: %w", err)
}
regularTx, err := conn.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to begin regular tx: %w", err)
}
// The journal counter and rows must commit in the SAME SQL transaction as
// every mutation they describe. bd_events_journal and bd_events_seq are
// dolt_ignored, so on the default split-transaction shape they would land in
// the ignored transaction while the mutation lands in the regular one: a
// mixed durable+wisp callback would then make the two transactions contend
// with each other on the single bd_events_seq row, and the ignored commit
// can fail AFTER the regular side has already committed — a mutation with no
// journal record, which is exactly the state the same-transaction guarantee
// exists to make impossible. In journal mode both planes therefore share the
// pinned regular transaction. The default journal-off path keeps the
// established split transactions untouched.
journalEnabled := s.eventsJournalEnabled.Load()
ignoredTx := regularTx
if !journalEnabled {
// NOTE (GH#3140 metrics skew): the pool-wait bracket above measures only
// the FIRST acquisition (the regular conn). A borrow insideView on GitHub (pinned to 71377f2769)
Solutions
- Retry the operation — this is a pre-callback setup failure and withTransactionSetupRetry will retry it
- Check Dolt server logs for shutdown/storage errors at the failure time
- Widen the context deadline if it expired during BeginTx
- Ensure only one process has the embedded Dolt database open if running in embedded mode
Defensive patterns
Strategy: retry
Try / catch
// runInTransaction already retries pre-callback failures via withTransactionSetupRetry;
// if you handle it manually:
if err != nil && callbackNotStarted(err) {
return withTransactionSetupRetry(ctx, attempt)
} Prevention
- Let the library's setup-retry wrapper handle retries instead of rolling your own
- Keep network paths to the Dolt server stable (avoid aggressive NAT timeouts)
- Avoid starting writes during known shutdown/maintenance windows
- Give BeginTx-bearing operations sane (seconds, not milliseconds) deadlines
When it happens
Trigger: ctx canceled/deadline exceeded exactly during BeginTx; connection dropped after `SELECT active_branch()` succeeded; Dolt server refusing new transactions (shutdown, storage error); server-side session killed.
Common situations: Flaky network to a remote Dolt server; graceful-shutdown windows where the server stops accepting transactions; embedded Dolt process exiting under memory pressure; very tight per-operation timeouts.
Related errors
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to begin ignored tx: %w
- ErrTransaction
- failed to recompute is_blocked: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/73ae7bf1b5d86b86.
Report an issue: GitHub.