gastownhall/beads · error

delete: affected by deletion

Error message

delete: affected by deletion: %w

What it means

deleteMany wraps errors from issueRepo.AffectedByDeletion, which finds remaining issues whose text references or dependencies point at the IDs being deleted. The 'delete: affected by deletion:' prefix marks this step; the driver error is preserved via %w. Depending on where the failure occurs, some delete steps (e.g. dependency drops) may already have partially completed.

Solutions

  1. Inspect the wrapped AffectedByDeletion error to find the driver failure
  2. Verify Dolt is reachable and check for a partially completed delete before retrying
  3. Re-run the delete; the operation is designed to be resumable/re-runnable
  4. If schema errors persist, run the beads migration path

Example fix

// before
res, err := uc.DeleteIssues(ctx, ids, actor)
if err != nil { return err }
// after
if err != nil {
	if strings.Contains(err.Error(), "affected by deletion") {
		log.Printf("delete may be partially applied, verify state: %v", err)
	}
	return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

if err := pingDolt(ctx); err != nil {
	return fmt.Errorf("storage unavailable, deferring delete: %w", err)
}

Try / catch

res, err := uc.DeleteIssues(ctx, ids, actor)
if err != nil && strings.Contains(err.Error(), "affected by deletion") {
	// failure late in the pipeline: verify delete state, then re-run
	log.Printf("delete interrupted at cross-reference check: %v", err)
	return verifyAndRetryDelete(ctx, ids)
}

Prevention

When it happens

Trigger: Any deleteMany invocation reaching the post-dry-run phase when AffectedByDeletion(ctx, regularIDs, wispIDs) fails — DB connection error, SQL error in the cross-reference query, storage unavailable mid-delete.

Common situations: Deletes of widely-referenced issues with many text references under load; Dolt restart mid-operation; schema drift on the issues/wisps tables.

Related errors


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

Appendix: source

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

		return result, nil
	}

	var connected map[string]*types.Issue
	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)

View on GitHub (pinned to 71377f2769)