gastownhall/beads · error
begin is_blocked recompute: %w
Error message
begin is_blocked recompute: %w
What it means
RecomputeAllBlockedOnConn opens a transaction for the is_blocked recompute and wraps BeginTx failure as "begin is_blocked recompute: <cause>". It throws when the connection cannot start a transaction — the database is closed, the connection is broken, or the driver rejects the isolation level. No recompute work has happened yet, so it is safe to retry.
Source
Thrown at internal/storage/versioncontrolops/blocked_recompute.go:73
// RecomputeAllBlockedOnConn runs the whole full is_blocked repair on conn and
// returns the number of rows it corrected: guard + recompute inside one
// transaction, then — only when something actually changed — stage `issues`
// alone and commit under BlockedRecomputeCommitMsg.
//
// author may be empty, which omits --author and lets the server attribute the
// commit to the connected session. That is the right default for the
// proxied-server plane, whose every other commit (uow.Tx.Commit) is likewise
// unauthored; a store that has a configured committer identity passes it.
//
// The returned count is meaningful even alongside a non-nil error from the
// staging step: the rows WERE corrected in the working set, only the history
// entry failed, and a caller that reported 0 there would be lying about the
// database it is looking at.
func RecomputeAllBlockedOnConn(ctx context.Context, conn BlockedRecomputeConn, author string) (int64, error) {
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
return 0, fmt.Errorf("begin is_blocked recompute: %w", err)
}
changed, err := GuardedRecomputeAllBlockedInTx(ctx, tx)
if err != nil {
_ = tx.Rollback()
return 0, err
}
if err := tx.Commit(); err != nil {
return 0, fmt.Errorf("commit is_blocked recompute: %w", err)
}
if changed > 0 {
if err := StageAndCommit(ctx, conn, BlockedRecomputeStagedTables(), BlockedRecomputeCommitMsg, author); err != nil {
return changed, err
}
}
return changed, nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Check that the DB connection is open and healthy before calling
- Retry with backoff if the cause is a transient connection/lock error
- Inspect the wrapped cause for driver-specific lock or close messages
- Avoid calling concurrently with operations that hold long write transactions
Example fix
// before
n, err := vcops.RecomputeAllBlockedOnConn(ctx, conn, "agent")
// after
if err := conn.PingContext(ctx); err != nil {
return fmt.Errorf("db unavailable: %w", err)
}
n, err := vcops.RecomputeAllBlockedOnConn(ctx, conn, "agent")
if err != nil { return fmt.Errorf("recompute: %w", err) } Defensive patterns
Strategy: retry
Validate before calling
if err := conn.PingContext(ctx); err != nil {
return fmt.Errorf("db not ready: %w", err)
} Try / catch
n, err := vcops.RecomputeAllBlockedOnConn(ctx, conn, author)
if err != nil {
if strings.Contains(err.Error(), "begin is_blocked recompute") && isTransient(errors.Unwrap(err)) {
return retryWithBackoff(3, func() error {
_, e := vcops.RecomputeAllBlockedOnConn(ctx, conn, author); return e
})
}
return err
} Prevention
- Ping the connection before long recompute jobs
- Avoid running during shutdown or while db.Close() may execute
- Keep transactions short to reduce lock contention with other writers
When it happens
Trigger: RecomputeAllBlockedOnConn(ctx, conn, author) when conn.BeginTx fails: connection closed/pooled-broken, database locked by another writer in restrictive drivers, or invalid tx options.
Common situations: Calling after db.Close() or during shutdown; connection dropped by a network hiccup or server idle timeout; concurrent long-running writer transactions blocking new ones.
Related errors
- ErrTransaction
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to begin transaction: %w
- failed to commit dependency key repairs: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/05527517fb198f9c.
Report an issue: GitHub.