gastownhall/beads · error
delete: list wisp dependents: %w
Error message
delete: list wisp dependents: %w
What it means
This error wraps a failure from depRepo.ListByIssueIDs with UseWispsTable=true and Direction=DepDirectionIn in externalDependents. Unlike the issue-table query, a table-not-exist error is tolerated (wisps may never have been created in this DB); any other failure aborts the delete/preview flow.
Source
Thrown at internal/storage/domain/issue_delete.go:236
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] {
continue
}
seen[target][d.IssueID] = true
out[target] = append(out[target], d.IssueID)View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error and exclude dberrors.IsTableNotExist cases (those are expected and ignored by design).
- Fix the underlying connection/timeout issue and retry the delete.
- Run a DB consistency/migration check if the wisps table exists but queries fail on schema.
- If wisps are unused in your deployment, confirm the table truly doesn't exist — that path is silently skipped.
Defensive patterns
Strategy: try-catch
Validate before calling
// Only surface unexpected errors; missing wisps table is tolerated upstream:
// ensure your DB either has the wisps tables migrated or none at all.
if err := migrate(ctx); err != nil {
return fmt.Errorf("schema check failed: %w", err)
} Type guard
var dbErr *dberrors.DBError
if errors.As(err, &dbErr) && !dberrors.IsTableNotExist(err) {
// real failure, not the tolerated missing-wisps-table case
} Try / catch
_, err := uc.DeleteWisps(ctx, ids, opts)
if err != nil && strings.Contains(err.Error(), "delete: list wisp dependents") {
if dberrors.IsTableNotExist(errors.Unwrap(err)) {
return nil // tolerated by design
}
return err
} Prevention
- Run beads migrations so wisps tables match the binary version
- Distinguish IsTableNotExist (tolerated) from other driver errors
- Avoid concurrent wisp writes during delete operations
- Retry transient connection failures
When it happens
Trigger: deleteMany -> externalDependents when the wisps dependency table exists but the incoming-dependency query against it fails for reasons other than table-not-exist: connection error, timeout, scan failure.
Common situations: Wisps table present but locked or corrupted; connection dropped mid-query; driver version mismatch after a beads upgrade altering the wisps schema.
Related errors
- collectConnected (wisps): %w
- no store is open for this workspace
- load dependency records: %w
- load wisp dependency counts: %w
- wisp plane membership: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2b0af6b82e561eea.
Report an issue: GitHub.