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

  1. Check database connectivity and that the Dolt server/db file is reachable and not locked
  2. Retry the update — begin failures are often transient
  3. Inspect the wrapped cause (%w) for driver-specific diagnostics (pool timeout, locked DB, canceled context)
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/bb041fe759e9da1c. Report an issue: GitHub.