gastownhall/beads · error
affected by status change for %s: %w
Error message
affected by status change for %s: %w
What it means
After a status change, updateIssueInTx computes which dependent issues/wisps were affected (AffectedByStatusChangeInTx or its wisp variant) and wraps any failure as "affected by status change for %s: %w". This bookkeeping is required to recompute is_blocked on dependents, so a failure aborts the update transaction.
Source
Thrown at internal/storage/issueops/update.go:529
var newStatus string
switch v := rawStatus.(type) {
case string:
newStatus = v
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, nilView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error from the AffectedByStatusChange* call for the root SQL failure.
- Check dependency table integrity (orphaned/deleted referenced ids) and clean up stale dependencies.
- Retry the transaction if the error is transient (timeout, connection).
- If the graph is very large, split the status change or verify dependency query performance/indexes.
Example fix
// before
_, err := storage.UpdateIssueInTx(ctx, tx, issueTable, eventTable, id, map[string]interface{}{"status": "closed"}, actor)
// after (retry transient failures)
for i := 0; i < 3; i++ {
if _, err := storage.UpdateIssueInTx(ctx, tx, issueTable, eventTable, id, map[string]interface{}{"status": "closed"}, actor); err == nil {
break
}
} Defensive patterns
Strategy: retry
Validate before calling
// pre-check dependency integrity before a status change
if err := storage.ValidateDependencies(ctx, id); err != nil {
return fmt.Errorf("stale dependencies on %s: %w", id, err)
} Try / catch
if _, err := storage.UpdateIssue(ctx, id, map[string]interface{}{"status": "closed"}, actor); err != nil {
if strings.Contains(err.Error(), "affected by status change") && isTransient(err) {
// backoff and retry the whole transaction
}
return err
} Prevention
- Clean up dependencies pointing at deleted issues before status changes.
- Keep dependency graphs bounded; split very wide status-change fan-outs.
- Use bounded retries for transient DB errors during the recompute step.
- Monitor timeouts on the affected-issues query as the graph grows.
When it happens
Trigger: A status-changing update triggers AffectedByStatusChangeInTx / AffectedByStatusChangeForWispInTx, which fails — typically a dependency-query SQL error, missing dependency table, or connection issue during the affected-rows query.
Common situations: Large dependency graphs making the affected-query slow or timing out; schema drift in dependency tables; Dolt connection drops mid-transaction; corrupt dependency rows referencing deleted issues.
Related errors
- retarget inbound dependencies to wisp in %s for %s: %w
- record dependency_removed event: %w
- recompute is_blocked after status change for %s: %w
- no store is open for this workspace
- failed to create issue: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/149dd0dcd29c18c0.
Report an issue: GitHub.