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

  1. Check DB connectivity and that the 'dependencies' table exists in the current schema (run bd doctor / schema migration).
  2. Retry the delete; the operation is transaction-scoped so no partial dependency rows are left behind.
  3. Inspect the wrapped cause (%w chain) for the specific driver error (deadlock, lock wait timeout, permission) and fix that.
  4. If running against an embedded Dolt database, verify no competing process holds conflicting locks.
  5. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/a125074089800bee. Report an issue: GitHub.