gastownhall/beads · error

failed to commit is_blocked repairs: %w

Error message

failed to commit is_blocked repairs: %w

What it means

After the is_blocked recompute succeeds inside the transaction, repairBlockedState calls tx.Commit() to persist the corrected rows to the working set. This error wraps a failed commit; the transaction's changes are lost and nothing was repaired. Note it does not roll back explicitly (commit failure already terminates the tx), and no DOLT_ADD/DOLT_COMMIT staging happens afterward — so the failure is contained to the SQL transaction layer.

Source

Thrown at cmd/bd/doctor/fix/blocked.go:71

		return fmt.Errorf("failed to begin transaction: %w", err)
	}
	// Refuse to derive and commit is_blocked from a dirty graph: like the store
	// paths, the recompute reads the working set and stages only `issues`, so a
	// dirty issues/dependencies tree would taint the repair commit (bd-6dnrw.37).
	// In a `bd doctor --fix` run the dependency-graph fixes commit ahead of this
	// one, so the tree is normally clean here; when it is not, surface it as an
	// actionable error rather than committing tainted state.
	if err := issueops.GuardBlockedRecomputeWorkingSet(ctx, tx); err != nil {
		_ = tx.Rollback()
		return err
	}
	changed, err := issueops.RecomputeAllIsBlockedInTx(ctx, tx)
	if err != nil {
		_ = tx.Rollback()
		return fmt.Errorf("failed to recompute is_blocked: %w", err)
	}
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("failed to commit is_blocked repairs: %w", err)
	}

	if changed == 0 {
		fmt.Println("  is_blocked already consistent — nothing to fix")
		return nil
	}

	// Persist the corrected flags as a Dolt commit, staging only issues — the
	// synced table is_blocked lives on (wisps are dolt_ignore'd). This path keeps
	// its own fresh-DB lifecycle rather than the shared store helper, but it must
	// not report success on a failed commit: a swallowed DOLT_COMMIT error would
	// leave the repair in the working set only, silently undone by the next pull.
	// bd doctor is server-mode only, so the server supplies the commit identity.
	if _, err := db.ExecContext(ctx, "CALL DOLT_ADD(?)", "issues"); err != nil {
		return fmt.Errorf("failed to stage is_blocked repairs: %w", err)
	}
	if _, err := db.ExecContext(ctx, "CALL DOLT_COMMIT('-m', 'doctor: recompute is_blocked for all issues')"); err != nil && !issueops.IsNothingToCommitError(err) {
		return fmt.Errorf("failed to commit is_blocked repairs to Dolt: %w", err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped %w cause; if it is a dead/timed-out connection, simply rerun `bd doctor --fix` with a fresh connection.
  2. Ensure the Dolt server is writable — a read-only server or replica will reject the commit; point bd at the primary.
  3. Rerun the fix when contention is suspected: commit failures from lock conflicts resolve once the competing process finishes.
  4. For large databases timing out, increase connection idle/timeout settings or run the repair against the server directly on localhost.

Example fix

// before (read-only replica)
err: failed to commit is_blocked repairs: Error 1227: server is running with --read-only

// after: target the writable primary
beadsDir = primaryBeadsDir // not the replica checkout
err := fix.RecomputeBlocked(beadsDir)
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the target server accepts writes before the repair
var readonly int
if err := db.QueryRow("SELECT @@read_only").Scan(&readonly); err == nil && readonly == 1 {
	log.Fatal("Dolt server is read-only — point bd at the writable primary")
}

Type guard

func isDeadConnCommitErr(err error) bool {
	return err != nil && (errors.Is(err, sql.ErrConnDone) ||
		strings.Contains(err.Error(), "bad connection") ||
		strings.Contains(err.Error(), "driver: timeout"))
}

Try / catch

if err := repairBlockedState(ctx, db); err != nil && isDeadConnCommitErr(err) {
	// recompute rolled back with the tx — safe to retry on a fresh handle
	db.Close()
	if db, _, err = openDoltDB(beadsDir); err == nil {
		err = repairBlockedState(ctx, db)
	}
}

Prevention

When it happens

Trigger: Calling fix.RecomputeBlocked when tx.Commit() fails: the connection to the Dolt server dropped between recompute and commit, the server rejected the commit (lock conflict, deadlock, session killed), the context/deadline expired mid-commit, or the server is read-only (--read-only replica) and refuses writes.

Common situations: Long recompute exceeded a connection idle timeout so the session died before commit; another process held conflicting locks on the issues table; pointing bd at a read-only Dolt replica or a server started read-only; network blip between client and server during a large update.

Related errors


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