gastownhall/beads · error
failed to begin transaction: %w
Error message
failed to begin transaction: %w
What it means
updateWisp could not start a database transaction via s.db.BeginTx; the driver's error is wrapped as 'failed to begin transaction'. Nothing was modified — the failure happens before any wisp update SQL runs. This points to database connectivity/availability rather than the update itself.
Source
Thrown at internal/storage/dolt/wisps.go:191
var labels []string
for rows.Next() {
var label string
if err := rows.Scan(&label); err != nil {
return nil, wrapScanError("scan wisp label", err)
}
labels = append(labels, label)
}
return labels, rows.Err()
}
// updateWisp updates fields on a wisp in the wisps table.
// Delegates SQL work to issueops.UpdateIssueInTx; no Dolt versioning needed
// since wisps live in dolt_ignored tables.
func (s *DoltStore) updateWisp(ctx context.Context, id string, updates map[string]interface{}, actor string) error {
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
defer func() { _ = tx.Rollback() }()
clearJournalScope := s.scopeEventsJournalTransaction(tx)
defer clearJournalScope()
if _, err := issueops.UpdateIssueInTx(ctx, tx, id, updates, actor); err != nil {
return err
}
return s.commitSQLTx(ctx, "commit update wisp", tx)
}
// updateWispChecked updates a wisp with the optional atomic preconditions of
// UpdateIssueChecked, mirroring updateWisp but first enforcing — in the SAME
// transaction — opts.ExpectedVersion (issueops.CheckVersionInTx →
// storage.ErrVersionMismatch) and the opts.ExpectedAssignee/ExpectedStatus
// field guards (issueops.CheckExpectedFieldsInTx → ErrAssigneeMismatch/View on GitHub (pinned to 71377f2769)
Solutions
- Check database connectivity and that the Dolt server/db file is reachable and not locked
- Retry the update — begin failures are often transient
- Inspect the wrapped cause (%w) for driver-specific diagnostics (pool timeout, locked DB, canceled context)
- Reduce concurrency or raise connection-pool limits if pool exhaustion recurs
Defensive patterns
Strategy: retry
Validate before calling
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("database unreachable before update: %w", err)
} Try / catch
err := store.UpdateIssue(ctx, id, updates)
if err != nil && strings.Contains(err.Error(), "failed to begin transaction") {
return retryWithBackoff(3, 500*time.Millisecond, func() error {
return store.UpdateIssue(ctx, id, updates)
})
} Prevention
- Ping the database or check connectivity before write batches
- Use contexts with realistic deadlines; avoid pre-canceled contexts
- Watch for DB file locks / Dolt server availability during deploys
- Cap concurrency so the connection pool is not exhausted
When it happens
Trigger: Called from updateIssue for an ephemeral wisp when the underlying Dolt/SQL connection pool is exhausted, the database is closed/locked, or the context is already canceled at BeginTx time.
Common situations: Database file locked by another process or server unavailable; connection pool saturated under high concurrency; ctx canceled/expired before the update; Dolt server restarting during deploys.
Related errors
- ErrTransaction
- open unit of work: %w
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to begin transaction: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/bb041fe759e9da1c.
Report an issue: GitHub.