gastownhall/beads · error
recompute is_blocked after source-repo delete: %w
Error message
recompute is_blocked after source-repo delete: %w
What it means
After deletion and journaling, RecomputeIsBlockedInTx refreshes the is_blocked flag for affected issues/wisps; failure is wrapped as "recompute is_blocked after source-repo delete: %w". The delete and journal succeeded but the derived blocked-state update failed, so the transaction should roll back to avoid stale is_blocked values.
Source
Thrown at internal/storage/issueops/bulk_ops.go:234
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("rows affected: %w", err)
}
// Journal each deleted issue in the same transaction. issueIDs is the exact
// set removed by the DELETE above (both were scoped to source_repo), so
// there are no phantom records here. The source-repo bulk delete plumbing
// carries no actor, so the rows record none.
for _, id := range issueIDs {
if err := RecordDeleteInTx(ctx, tx, id, ""); err != nil {
return int(rowsAffected), err
}
}
if err := RecomputeIsBlockedInTx(ctx, tx, affectedIssues, affectedWisps); err != nil {
return int(rowsAffected), fmt.Errorf("recompute is_blocked after source-repo delete: %w", err)
}
return int(rowsAffected), nil
}
//nolint:gosec // G201: table names are hardcoded
func UpdateIssueIDInTx(ctx context.Context, tx *sql.Tx, oldID, newID string, issue *types.Issue, actor string) error {
// Capture the edges under the OLD id before the rename rewrites them; they
// are what the journal replays as a remove/re-add pair around the identity
// change.
var renameEdges []journalDependencyEdge
if journalEnabled(ctx, tx) {
var err error
renameEdges, err = dependencyEdgesForIssueIDsInTx(ctx, tx, []string{oldID})
if err != nil {
return fmt.Errorf("capture dependency edges for rename %s -> %s: %w", oldID, newID, err)
}
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the inner error from RecomputeIsBlockedInTx for the failing statement
- Retry the whole transaction; it is atomic so no partial delete persists
- Increase the context timeout for repos with wide dependency graphs
- Verify schema (is_blocked column and dependency tables) is current
Defensive patterns
Strategy: retry
Validate before calling
// pre-check is_blocked column and dependencies tables exist
_, err := db.Query("SELECT is_blocked FROM issues LIMIT 1") Type guard
if errors.Is(err, context.DeadlineExceeded) { /* recompute timed out: retry with longer budget */ } Try / catch
err := DeleteIssuesBySourceRepoInTx(ctx, tx, repo)
if err != nil && strings.Contains(err.Error(), "recompute is_blocked") {
tx.Rollback() // avoid stale is_blocked state
// retry entire transaction with a larger timeout
} Prevention
- Always roll back if the recompute fails — half-deleted state with stale flags is worse than no delete
- Allow long contexts for repos with wide dependency graphs
- Keep schema current so is_blocked and dependency tables match the recompute query
When it happens
Trigger: RecomputeIsBlockedInTx errors: its UPDATE/SELECT over affected issues fails (missing columns, locked DB), the affected set is enormous and the context times out, or an earlier journal write poisoned the tx.
Common situations: Large cross-repo dependency graphs making the recompute slow; schema drift on is_blocked; concurrent writers locking the tables during the update.
Related errors
- ErrTransaction
- open unit of work: %w
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to begin transaction: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5f83714caba5b062.
Report an issue: GitHub.