gastownhall/beads · error
failed to begin transaction: %w
Error message
failed to begin transaction: %w
What it means
repairDependencyKeys wraps all writes in an explicit transaction so repairs persist even when the Dolt server runs with @@autocommit OFF. If db.Begin() fails — the pool cannot obtain a usable connection or start a transaction — this error wraps that cause and the repair aborts with no changes applied.
Source
Thrown at cmd/bd/doctor/fix/dep_keys.go:116
// repairDependencyKeys scans and repairs rekey-backfill leftovers on an open
// connection. Split from DependencyKeys so the repair logic is testable
// against an existing store handle.
func repairDependencyKeys(ctx context.Context, db *sql.DB, verbose bool) error {
anomalies, err := ScanDependencyKeys(ctx, db)
if err != nil {
return fmt.Errorf("failed to scan dependency keys: %w", err)
}
if len(anomalies) == 0 {
fmt.Println(" No dependency key anomalies to fix")
return nil
}
// Uses explicit transaction so writes persist when @@autocommit is OFF
// (e.g. Dolt server started with --no-auto-commit).
tx, err := db.Begin()
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
var rekeyed, removed, failed int
repairedTables := make(map[string]bool)
for _, a := range anomalies {
showIndividual := verbose || len(a.MisKeyed)+len(a.NullTarget) < 20
for _, mk := range a.MisKeyed {
//nolint:gosec // G201: table is a hardcoded constant, never user input.
if _, err := tx.Exec(fmt.Sprintf(`UPDATE %s SET id = ? WHERE id = ?`, a.Table), mk[1], mk[0]); err != nil {
fmt.Printf(" Warning: failed to re-key %s row %s (row keeps its old id): %v\n", a.Table, mk[0], err)
failed++
continue
}
rekeyed++
repairedTables[a.Table] = true
if showIndividual {
fmt.Printf(" Re-keyed %s row %s → %s\n", a.Table, mk[0], mk[1])
}
}View on GitHub (pinned to 71377f2769)
Solutions
- Retry the command — transient connection loss is the most common cause
- Ensure the Dolt server is running and healthy (bd doctor / server logs)
- Set reasonable pool limits/timeouts (SetMaxOpenConns, ConnMaxLifetime) so connections don't go stale
Example fix
// before
if err := repairDependencyKeys(ctx, db, verbose); err != nil { ... } // failed to begin transaction
// after: warm/validate the connection first
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("database unreachable: %w", err)
}
if err := repairDependencyKeys(ctx, db, verbose); err != nil { ... } Defensive patterns
Strategy: retry
Validate before calling
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("DB unreachable, refusing to begin repair transaction: %w", err)
} Try / catch
err := repairDependencyKeys(ctx, db, verbose)
if err != nil && strings.Contains(err.Error(), "failed to begin transaction") {
time.Sleep(2 * time.Second)
err = repairDependencyKeys(ctx, db, verbose) // Begin failure = nothing written; retry safe
} Prevention
- Configure the sql pool (SetConnMaxLifetime, Ping timeout) so stale connections are recycled
- Avoid concurrent bd writers against the same DB during repairs
- Ensure the Dolt server is fully up (health check) before running fixes
When it happens
Trigger: Calling DependencyKeys/repairDependencyKeys when db.Begin() fails: connection pool exhausted, connection dropped between scan and Begin, or the Dolt server rejecting transaction start (e.g. server shutting down, --no-auto-commit server in a bad state).
Common situations: Long doctor run over a flaky connection where the pool connection goes stale before Begin; Dolt server restarted mid-fix; too many concurrent bd processes holding connections.
Related errors
- failed to commit dependency key repairs: %w
- ErrTransaction
- failed to load config: %w
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/02d3c4d61ebaa684.
Report an issue: GitHub.