gastownhall/beads · error

recompute is_blocked after status change for %s: %w

Error message

recompute is_blocked after status change for %s: %w

What it means

This error wraps a failure while recomputing the is_blocked flag for issues that depend on an issue whose status just changed. After a status update inside a transaction, issueops recalculates blocked state for all affected issues/wisps via RecomputeIsBlockedInTxWithResult; if that recompute query fails, the whole update transaction is rolled back and this wrapped error is returned.

Source

Thrown at internal/storage/issueops/update.go:533

		case types.Status:
			newStatus = string(v)
		}
		oldActive := oldIssue.Status != types.StatusClosed && oldIssue.Status != types.StatusPinned
		newActive := newStatus != string(types.StatusClosed) && newStatus != string(types.StatusPinned)
		if oldActive != newActive {
			var affectedIssues, affectedWisps []string
			var aerr error
			if isWisp {
				affectedIssues, affectedWisps, aerr = AffectedByStatusChangeForWispInTx(ctx, tx, id)
			} else {
				affectedIssues, affectedWisps, aerr = AffectedByStatusChangeInTx(ctx, tx, id)
			}
			if aerr != nil {
				return nil, fmt.Errorf("affected by status change for %s: %w", id, aerr)
			}
			recompute, err := RecomputeIsBlockedInTxWithResult(ctx, tx, affectedIssues, affectedWisps)
			if err != nil {
				return nil, fmt.Errorf("recompute is_blocked after status change for %s: %w", id, err)
			}
			updateResult.IssueRowsChanged = !isWisp || recompute.IssueRowsChanged
			updateResult.WispRowsChanged = isWisp || recompute.WispRowsChanged
		}
	}

	// Snapshot only after all derived blocked-state maintenance has completed,
	// so the journal row carries the settled bead. recordEvent controls the
	// human-facing audit event only: the journal is a machine replay feed and
	// must never have a hole punched in it by an audit-suppressing caller.
	if err := RecordEventInTx(ctx, tx, EventUpdate, id, actor); err != nil {
		return nil, err
	}
	return updateResult, nil
}

func cloneUpdateFields(updates map[string]interface{}) map[string]interface{} {
	cloned := make(map[string]interface{}, len(updates))

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped %w cause to identify the underlying SQL/DB error and fix that first
  2. Retry the update transaction; the recompute runs inside the same tx so a transient DB error is safe to retry
  3. Verify dependency rows (blocked-by relations) are consistent, e.g. via a data-integrity check or re-sync
  4. If reproducible, capture the failing query from RecomputeIsBlockedInTxWithResult and check schema/version compatibility

Example fix

// before
bd update bd-42 --status closed  // fails: recompute is_blocked after status change

// after
// 1. check the wrapped cause
bd doctor  # or inspect storage logs for the underlying SQL error
// 2. repair dangling dependency references, then retry the status change
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: verify dependency rows are consistent before a status change
rows, err := db.Query("SELECT issue_id FROM dependencies WHERE depends_on_id = ?", issueID)
if err != nil {
    return fmt.Errorf("cannot read dependencies, update would fail recompute: %w", err)
}

Try / catch

// wrap in retry with backoff for transient DB errors
for i := 0; i < 3; i++ {
    _, err := issueops.UpdateIssueInTx(ctx, tx, id, updates)
    if err == nil || !strings.Contains(err.Error(), "recompute is_blocked") {
        break
    }
    time.Sleep(backoff(i))
}

Prevention

When it happens

Trigger: Calling UpdateIssueInTx or UpdateIssueWithoutEventInTx with a status-changing update (e.g. closing an issue) while its dependency graph rows are in a state the recompute SQL cannot handle, or when the underlying database errors during the recompute statement.

Common situations: Database connectivity drops mid-transaction, dependency rows reference issues in unexpected states, schema/lock contention during bulk status changes, or corrupted dependency edges left from a prior failed migration.

Related errors


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