gastownhall/beads · error

begin is_blocked recompute: %w

Error message

begin is_blocked recompute: %w

What it means

Wraps a failure of db.BeginTx when starting the transaction for the full is_blocked recompute. Every recompute reads and writes inside a single transaction so the dirty-graph guard and recompute see the same working set; if the transaction cannot begin, the recompute aborts before doing any work.

Source

Thrown at internal/storage/dolt/store.go:4589

	}
	defer conn.Close()
	if err := s.pinStoreBranch(ctx, conn); err != nil {
		return 0, err
	}
	return s.recomputeAllBlockedWithDB(ctx, conn)
}

// txBeginner is satisfied by both *sql.DB and *sql.Conn, letting
// recomputeAllBlockedWithDB run either against a caller-owned pinned
// *sql.Conn (recomputeAllBlocked) or directly against a *sql.DB (tests).
type txBeginner interface {
	BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
}

func (s *DoltStore) recomputeAllBlockedWithDB(ctx context.Context, db txBeginner) (int, error) {
	tx, err := db.BeginTx(ctx, nil)
	if err != nil {
		return 0, fmt.Errorf("begin is_blocked recompute: %w", err)
	}
	// One shared body across every mode (guard a dirty graph, then recompute):
	// the guard refuses to derive and commit is_blocked from uncommitted
	// issue/dependency edits, and it runs inside THIS tx so it sees exactly the
	// working set the recompute reads (bd-6dnrw.37).
	changed, err := versioncontrolops.GuardedRecomputeAllBlockedInTx(ctx, tx)
	if err != nil {
		_ = tx.Rollback()
		return 0, err
	}
	if err := s.commitSQLTx(ctx, "commit is_blocked recompute", tx); err != nil {
		return 0, err
	}
	if changed > 0 {
		// Stage only issues — the synced table is_blocked lives on (wisps are
		// dolt_ignore'd) — so an unrelated dirty working set is not swept in.
		if err := s.doltAddAndCommit(ctx, blockedRecomputeStagedTableList(),
			versioncontrolops.BlockedRecomputeCommitMsg); err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry the recompute — a fresh connection will be acquired
  2. Check the wrapped cause for context cancellation and increase the timeout
  3. Verify Dolt server is up and accepting connections
  4. If ErrBadConn recurs, confirm the server's idle timeout is not shorter than bd's long-timeout setting
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the connection is alive before beginning work
if err := conn.PingContext(ctx); err != nil {
    // re-acquire the connection; the old one is bad
}

Try / catch

if err := store.RecomputeAllBlocked(ctx); err != nil {
    if strings.Contains(err.Error(), "begin is_blocked recompute") {
        // transient: retry once with a fresh connection
        time.Sleep(time.Second)
        err = store.RecomputeAllBlocked(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: BeginTx returns an error on the pinned long-timeout connection — the underlying connection went bad (driver.ErrBadConn), the context was canceled before the transaction started, or the Dolt server rejected the new transaction (e.g. shutdown or too many connections).

Common situations: Connection sat idle past server wait_timeout and was dropped; Dolt server restart between acquiring the connection and beginning the tx; context deadline exceeded.

Related errors


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