gastownhall/beads · error
delete: drop deps: %w
Error message
delete: drop deps: %w
What it means
This error wraps a failure while deleting dependency rows that originate from the regular issues being deleted. During deleteMany, after computing affected issues, the use case calls depRepo.DeleteAllForIDs for regular IDs; any storage-layer failure (Dolt/SQL error, connection loss, table missing) surfaces here prefixed 'delete: drop deps:'. It means the cascade delete of dependency edges for non-wisp issues could not complete and the whole delete aborts.
Source
Thrown at internal/storage/domain/issue_delete.go:167
var connectedIsWisp map[string]bool
if params.UpdateTextReferences {
deletedSet := make(map[string]bool, len(allIDs))
for _, id := range allIDs {
deletedSet[id] = true
}
connected, connectedIsWisp, err = u.collectConnectedIssues(ctx, allIDs, deletedSet)
if err != nil {
return result, err
}
}
affectedIssues, affectedWisps, err := u.issueRepo.AffectedByDeletion(ctx, regularIDs, wispIDs)
if err != nil {
return result, fmt.Errorf("delete: affected by deletion: %w", err)
}
if _, err := u.depRepo.DeleteAllForIDs(ctx, regularIDs, DepInsertOpts{}); err != nil {
return result, fmt.Errorf("delete: drop deps: %w", err)
}
if _, err := u.depRepo.DeleteAllForIDs(ctx, wispIDs, DepInsertOpts{UseWispsTable: true}); err != nil {
return result, fmt.Errorf("delete: drop wisp deps: %w", err)
}
// The SYNC-PLANE edges pointing at a deleted wisp, which are not the same
// rows as the line above and are not reached by a foreign key: there is no
// FK from dependencies to wisps, so `dependencies.depends_on_wisp_id` rows
// survive their target unless they are deleted explicitly. Without this a
// forced delete of a wisp left its durable dependent holding an edge into
// a row that no longer exists — dangling, not orphaned, which is not what
// issueops.DeleteRequest.Force promises. The store body has always done
// this (issueops.deleteIssueRowInTx -> DeleteWispFromDependenciesInTx).
if _, err := u.depRepo.DeleteAllForIDs(ctx, wispIDs, DepInsertOpts{}); err != nil {
return result, fmt.Errorf("delete: drop sync-plane edges into deleted wisps: %w", err)
}
if _, err := u.labelRepo.DeleteAllForIDs(ctx, regularIDs, LabelOpts{}); err != nil {
return result, fmt.Errorf("delete: drop labels: %w", err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Check DB connectivity and that the 'dependencies' table exists in the current schema (run bd doctor / schema migration).
- Retry the delete; the operation is transaction-scoped so no partial dependency rows are left behind.
- Inspect the wrapped cause (%w chain) for the specific driver error (deadlock, lock wait timeout, permission) and fix that.
- If running against an embedded Dolt database, verify no competing process holds conflicting locks.
- Ensure context deadlines are long enough for large ID batches.
Example fix
// before
err := store.DeleteIssues(ctx, ids, opts) // opaque 'delete: drop deps' failure
// after
if err := ctx.Err(); err != nil { return fmt.Errorf("ctx cancelled before delete: %w", err) }
if err := pingDB(ctx); err != nil { return fmt.Errorf("db not reachable: %w", err) }
err := store.DeleteIssues(ctx, ids, opts) Defensive patterns
Strategy: validation
Validate before calling
if err := ctx.Err(); err != nil { return err }
if err := db.PingContext(ctx); err != nil { return fmt.Errorf("db unreachable: %w", err) }
exists, err := tableExists(ctx, "dependencies"); if err != nil || !exists { return fmt.Errorf("dependencies table missing") } Type guard
var dbe *storage.DBError
if errors.As(err, &dbe) { /* inspect dbe.Cause for driver-level cause */ } Try / catch
if err := store.DeleteIssues(ctx, ids, opts); err != nil {
var blocked *domain.DeleteBlockedError
if errors.As(err, &blocked) { /* handle blocked delete */ }
if strings.Contains(err.Error(), "delete: drop deps:") { /* retry or report DB fault */ }
} Prevention
- Keep schema migrations current for the embedded Dolt store.
- Set generous context timeouts for batch deletes.
- Verify DB connectivity before large delete operations.
- Avoid running concurrent writers against the same database file.
When it happens
Trigger: Calling DeleteIssue/DeleteIssues (or the mixed DeleteWisps paths with regular IDs present) when the underlying dependencies table is unreadable/unwritable, the DB connection drops mid-transaction, or the driver returns an SQL error on DELETE.
Common situations: Database unavailable or restarted mid-operation; schema migration missed so the dependencies table does not exist; permission denied on the DB user; context cancelled during a long batch delete.
Related errors
- delete: drop wisp deps: %w
- delete: count deps: %w
- failed to remove relates-to %s -> %s: %w
- failed to get dependencies for %s: %w
- add deps: classify sources: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a125074089800bee.
Report an issue: GitHub.