gastownhall/beads · error
recompute is_blocked after batch delete: %w
Error message
recompute is_blocked after batch delete: %w
What it means
After rows are deleted and journaled, DeleteResolvedSetInTx recomputes the is_blocked flag on issues that depended on the deleted ones. Failure of RecomputeIsBlockedInTx is wrapped with this message. The rows are already deleted in this transaction, so a failure here rolls everything back.
Source
Thrown at internal/storage/issueops/delete.go:346
fmt.Sprintf(`DELETE FROM leases WHERE issue_id IN (%s)`, batchInClause),
batchArgs...); err != nil {
return nil, fmt.Errorf("delete leases: %w", err)
}
}
result.DeletedCount = totalRegularsDeleted + len(set.WispIDs)
// Journal every regular issue this bulk/cascade delete removed. Wisps went
// through deleteIssueRowInTx above, which journals each itself; set.All is
// cascade-expanded, so this records cascade deletes too. The delete
// plumbing carries no actor, so the rows record none.
for _, id := range journaledDeletes {
if err := RecordDeleteInTx(ctx, tx, id, ""); err != nil {
return nil, err
}
}
if err := RecomputeIsBlockedInTx(ctx, tx, affectedIssues, affectedWisps); err != nil {
return nil, fmt.Errorf("recompute is_blocked after batch delete: %w", err)
}
return result, nil
}
// ExistingIssueIDsInTableInTx returns the requested IDs that currently exist
// in the selected issue table. It preserves caller ordering so delete and
// journal records are deterministic across batches.
func ExistingIssueIDsInTableInTx(ctx context.Context, tx DBTX, table string, ids []string) ([]string, error) {
if len(ids) == 0 {
return nil, nil
}
switch table {
case "issues", "wisps":
default:
return nil, fmt.Errorf("unsupported issue table %q", table)
}
exists := make(map[string]struct{}, len(ids))View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped inner error from RecomputeIsBlockedInTx for the root cause
- Increase the context timeout for large cascades
- Repair dependency-table consistency (bd doctor / integrity check) if the recompute queries fail on bad rows
- Retry the delete; the transaction is atomic so no partial state remains
Example fix
// before deleteCtx := ctx // after deleteCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) defer cancel() // pass deleteCtx so RecomputeIsBlockedInTx is not cut short
Defensive patterns
Strategy: retry
Validate before calling
// sanity-check dependency table integrity before a big cascade
rows, _ := db.Query("SELECT COUNT(*) FROM dependencies WHERE issue_id IS NULL OR depends_on_id IS NULL")
// nonzero NULL count => repair before deleting Try / catch
res, err := DeleteIssuesInTx(ctx, tx, ids, opts)
if err != nil && strings.Contains(err.Error(), "recompute is_blocked") {
// whole tx rolled back; retry with longer deadline after repair
return retryWithTimeout(ctx, ids, 2*time.Minute)
}
return err Prevention
- Run integrity checks (bd doctor) to keep dependency rows consistent
- Use generous context deadlines for cascade deletes
- Keep the dependency tables free of NULL/corrupt rows
When it happens
Trigger: DeleteIssuesInTx/DeleteInTx where the post-delete dependency recompute fails — corrupt or missing dependency rows, query error on dependencies/wisp_dependencies tables, or context cancellation during the recompute.
Common situations: Very large cascade deletes making the recompute slow enough to hit a context deadline; inconsistent dependency tables after a failed earlier sync.
Related errors
- recompute is_blocked after delete for %s: %w
- delete wisp %s: %w
- delete issues: %w
- delete leases: %w
- delete wisp %s from dependencies: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9518c239e1259dee.
Report an issue: GitHub.