gastownhall/beads · error
db: DependencySQLRepository.Delete: affected set: %w
Error message
db: DependencySQLRepository.Delete: affected set: %w
What it means
Wraps a failure from computing the set of issues/wisps affected by a dependency removal (AffectedByDepChangeInTx or AffectedByDepChangeForWispInTx). After the edge is deleted, the repository needs the transitive affected set to refresh is_blocked; if that query fails the delete is aborted with this error so blocked-state never goes stale.
Source
Thrown at internal/storage/domain/db/dependency.go:381
IssueID: issueID,
Type: types.EventDependencyRemoved,
Actor: actor,
NewValue: fmt.Sprintf("Removed dependency on %s", dependsOnID),
}, domain.RecordEventOpts{UseWispsTable: opts.UseWispsTable}); err != nil {
return domain.DepDeleteResult{}, fmt.Errorf("db: DependencySQLRepository.Delete: record dependency_removed event: %w", err)
}
}
dt := types.DependencyType(depType)
var affectedIssues, affectedWisps []string
var aerr error
if opts.UseWispsTable {
affectedIssues, affectedWisps, aerr = issueops.AffectedByDepChangeForWispInTx(ctx, r.runner, issueID, dependsOnID, dt)
} else {
affectedIssues, affectedWisps, aerr = issueops.AffectedByDepChangeInTx(ctx, r.runner, issueID, dependsOnID, dt)
}
if aerr != nil {
return domain.DepDeleteResult{}, fmt.Errorf("db: DependencySQLRepository.Delete: affected set: %w", aerr)
}
if err := issueops.RecomputeIsBlockedInTx(ctx, r.runner, affectedIssues, affectedWisps); err != nil {
return domain.DepDeleteResult{}, fmt.Errorf("db: DependencySQLRepository.Delete: recompute is_blocked: %w", err)
}
// Snapshot only after all derived blocked-state maintenance has completed.
// Never gated on opts.EmitEvent — a structural removal is as real to a
// replaying consumer as one from an explicit dep verb.
if err := issueops.RecordDepEventInTx(ctx, r.runner, issueops.EventDepRemove, issueID, depType, dependsOnID, depMetadata, actor); err != nil {
return domain.DepDeleteResult{}, err
}
return domain.DepDeleteResult{Found: true, Type: dt, DependsOnID: dependsOnID}, nil
}
func (r *dependencySQLRepositoryImpl) HasCycle(ctx context.Context, issueID, dependsOnID string) (bool, error) {
if issueID == "" || dependsOnID == "" {
return false, errors.New("db: DependencySQLRepository.HasCycle: issueID and dependsOnID must not be empty")View on GitHub (pinned to 71377f2769)
Solutions
- Re-run the Delete with a longer context timeout / larger deadline; it is idempotent (second run returns Found:false but still recomputes nothing needed).
- Check ctx cancellation: ensure the caller's context isn't expiring during the transitive query.
- Verify opts.UseWispsTable matches where the dependency was stored.
- Inspect DB health (locks, connection pool exhaustion) if failures cluster under load.
Example fix
// before ctx := context.Background() // unbounded or too-short deadline elsewhere res, err := deps.Delete(ctx, id, depID, actor, opts) // after ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() res, err := deps.Delete(ctx, id, depID, actor, opts)
Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return err }
if issueID == "" || dependsOnID == "" { return errors.New("ids required") } Try / catch
if err != nil && strings.Contains(err.Error(), "affected set") {
// retry with longer deadline; Delete is idempotent (Found:false if already deleted)
ctx2, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
_, err = deps.Delete(ctx2, issueID, depID, actor, opts)
} Prevention
- Use generous context timeouts for deletes on large dependency graphs.
- Avoid cancelling the context mid-delete; let the transaction finish.
- Keep the wisps/issues table flag consistent across insert and delete.
- Check DB health/locks before bulk dep-removal operations.
When it happens
Trigger: DependencySQLRepository.Delete succeeds in deleting the edge, then the recursive/transitive affected-set query fails: connection loss, query timeout on large dependency graphs, SQL syntax/schema mismatch, or context cancellation mid-query.
Common situations: Very large dependency graphs timing out; context deadline exceeded because caller set a short timeout; Dolt server restarted mid-transaction; wrong UseWispsTable flag selecting an empty/absent table.
Related errors
- ErrQuery
- failed to get federation peer: %w
- failed to list federation peers: %w
- failed to get comments: %w
- failed to check issue_counter for prefix %q: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4c4e46dd96662cc9.
Report an issue: GitHub.