gastownhall/beads · error

delete: drop labels: %w

Error message

delete: drop labels: %w

What it means

This error means deleting the label rows attached to the regular issues being deleted failed. During deleteMany's cascade, labelRepo.DeleteAllForIDs runs for regular IDs after dependencies are dropped; any storage error aborts the delete so labels and issues stay consistent.

Source

Thrown at internal/storage/domain/issue_delete.go:184

	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)
	}
	if _, err := u.labelRepo.DeleteAllForIDs(ctx, wispIDs, LabelOpts{UseWispsTable: true}); err != nil {
		return result, fmt.Errorf("delete: drop wisp labels: %w", err)
	}
	if _, err := u.eventsRepo.DeleteAllForIDs(ctx, regularIDs, RecordEventOpts{}); err != nil {
		return result, fmt.Errorf("delete: drop events: %w", err)
	}
	if _, err := u.eventsRepo.DeleteAllForIDs(ctx, wispIDs, RecordEventOpts{UseWispsTable: true}); err != nil {
		return result, fmt.Errorf("delete: drop wisp events: %w", err)
	}

	issuesDeleted, err := u.issueRepo.DeleteByIDs(ctx, regularIDs, IssueTableOpts{})
	if err != nil {
		return result, fmt.Errorf("delete: drop issue rows: %w", err)
	}
	wispsDeleted, err := u.issueRepo.DeleteByIDs(ctx, wispIDs, IssueTableOpts{UseWispsTable: true})
	if err != nil {
		return result, fmt.Errorf("delete: drop wisp rows: %w", err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Confirm the labels table exists and the DB user can delete from it.
  2. Retry the delete; the transactional cascade leaves no partial label removal.
  3. Inspect the wrapped driver error for the precise cause.
  4. Run schema migrations / bd doctor if the schema is stale.
Defensive patterns

Strategy: validation

Validate before calling

if err := ctx.Err(); err != nil { return err }
exists, err := tableExists(ctx, "labels"); if err != nil || !exists { return fmt.Errorf("labels table missing") }

Type guard

var dbe *storage.DBError
if errors.As(err, &dbe) { /* inspect driver cause */ }

Try / catch

if err := store.DeleteIssues(ctx, ids, opts); err != nil {
    if strings.Contains(err.Error(), "delete: drop labels:") { /* check DB perms/retry */ }
}

Prevention

When it happens

Trigger: DeleteIssue/DeleteIssues calls where the labels table is missing, locked, or the driver returns an SQL error on DELETE; context cancellation; connection loss mid-cascade.

Common situations: Schema not migrated (labels table absent in embedded DB); DB user lacks DELETE privilege; lock contention with a concurrent bd process.

Related errors


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