gastownhall/beads · error
delete: list dependents: %w
Error message
delete: list dependents: %w
What it means
This error wraps a failure from depRepo.ListByIssueIDs with Direction=DepDirectionIn (incoming dependencies) in externalDependents, which finds direct dependents of the ids being deleted that are not themselves in the delete set. The wisp-table variant tolerates a missing wisps table, but a failure on the main dependencies table is fatal for the delete flow.
Source
Thrown at internal/storage/domain/issue_delete.go:232
if err := u.issueRepo.RecomputeIsBlocked(ctx, affectedIssues, affectedWisps); err != nil {
return result, fmt.Errorf("delete: recompute is_blocked: %w", err)
}
return result, nil
}
// externalDependents finds the direct dependents of each id in ids that are
// not themselves in ids, across both the issue and wisp dependency tables.
// The result maps deletion-set id -> external dependent ids (unsorted).
func (u *issueUseCaseImpl) externalDependents(ctx context.Context, ids []string) (map[string][]string, error) {
idSet := make(map[string]bool, len(ids))
for _, id := range ids {
idSet[id] = true
}
issueRes, err := u.depRepo.ListByIssueIDs(ctx, ids, DepListOpts{Direction: DepDirectionIn})
if err != nil {
return nil, fmt.Errorf("delete: list dependents: %w", err)
}
wispRes, err := u.depRepo.ListByIssueIDs(ctx, ids, DepListOpts{Direction: DepDirectionIn, UseWispsTable: true})
if err != nil && !dberrors.IsTableNotExist(err) {
return nil, fmt.Errorf("delete: list wisp dependents: %w", err)
}
out := map[string][]string{}
seen := map[string]map[string]bool{}
for _, res := range []DepBulkResult{issueRes, wispRes} {
for target, deps := range res.Incoming {
for _, d := range deps {
if d.IssueID == "" || idSet[d.IssueID] {
continue
}
if seen[target] == nil {
seen[target] = map[string]bool{}
}
if seen[target][d.IssueID] {View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped driver error — fix connectivity or the underlying storage issue first.
- Reduce batch size if the id list is very large, and call delete in chunks.
- Retry the operation; the query is read-only and safe to re-run.
- Verify the dependencies table exists and is migrated in this database.
Defensive patterns
Strategy: retry
Validate before calling
// Validate ids before the call:
for _, id := range ids {
if id == "" {
return errors.New("empty issue id in delete set")
}
}
if err := store.PingContext(ctx); err != nil {
return fmt.Errorf("db unreachable: %w", err)
} Type guard
var dbErr *dberrors.DBError
if errors.As(err, &dbErr) {
// inspect dbErr.Code to distinguish connectivity vs scan errors
} Try / catch
_, err := uc.DeleteIssues(ctx, ids, opts)
if err != nil && strings.Contains(err.Error(), "delete: list dependents") {
// read-only phase failed; safe to retry with backoff
return retryWithBackoff(func() error { _, err := uc.DeleteIssues(ctx, ids, opts); return err })
} Prevention
- Chunk very large delete id lists
- Check DB connectivity before bulk deletes
- Keep schema migrations current
- Log wrapped causes for driver-level diagnosis
When it happens
Trigger: deleteMany -> externalDependents when the incoming-dependency bulk query on the regular dependencies table fails: DB unreachable, malformed ids, query timeout, or driver-level scan error.
Common situations: Database connection loss during delete; extremely long id lists producing oversized IN clauses; corrupted dependency rows failing to scan into types.Dependency.
Related errors
- no store is open for this workspace
- load dependency records: %w
- loading subgraph for %s: %w
- failed to delete child %s: %w
- failed to remove relates-to %s -> %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5320b4c212dcada4.
Report an issue: GitHub.