{"record":{"id":"9bbb0a9275d26824","repo":"gastownhall/beads","slug":"delete-w","errorCode":null,"errorMessage":"delete: %w","messagePattern":"delete: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/delete_role.go","lineNumber":140,"sourceCode":"\t\t} else {\n\t\t\torphaned := make(map[string]bool)\n\t\t\tfor _, deps := range external {\n\t\t\t\tfor _, id := range deps {\n\t\t\t\t\torphaned[id] = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.Orphaned = workapi.SortedDeleteIDs(orphaned)\n\t\t}\n\t}\n\n\t// THE DELETION SET IS RESOLVED ONCE, HERE, and the same value reaches the\n\t// neighborhood read, the deletion and the citation rewrite. Resolving it\n\t// twice drifts: a cascade rooted at a wisp landed in the rewrite set and not\n\t// in the delete, so those rows survived and their neighbors' descriptions\n\t// were rewritten to call them deleted. See DeletionSet.\n\tset, err := ResolveDeletionSetInTx(ctx, tx, ids, req.Cascade)\n\tif err != nil {\n\t\treturn publicops.DeleteResult{}, fmt.Errorf(\"delete: %w\", err)\n\t}\n\n\t// The neighborhood is read BEFORE the deletion, because after it the\n\t// edges that identify a neighbor are gone. It is read against the whole\n\t// deletion set — the cascade closure, not just the named ids — so a row\n\t// citing a cascade-deleted id is rewritten too.\n\tneighbors, err := deleteNeighborsInTx(ctx, tx, set.All)\n\tif err != nil {\n\t\treturn publicops.DeleteResult{}, err\n\t}\n\n\t// No guard argument to pass: this body has ALREADY answered the guard\n\t// question above, and DeleteResolvedSetInTx deletes what it is handed.\n\tdeleted, err := DeleteResolvedSetInTx(ctx, tx, set, req.DryRun)\n\tif err != nil {\n\t\treturn publicops.DeleteResult{}, err\n\t}\n\tresult.Deleted = deleted.DeletedCount","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/delete_role.go#L122-L158","documentation":"This wraps a failure from ResolveDeletionSetInTx, which computes the single deletion set (the cascade closure when Cascade=true) shared by the neighborhood read, the delete and the citation rewrite. The source notes the set is resolved exactly once because resolving it twice drifted — wisp-rooted cascade rows survived while their neighbors' text claimed they were deleted. A failure here aborts the whole delete before any write, so nothing is partially applied.","triggerScenarios":"DeleteInTx calls ResolveDeletionSetInTx(ids, req.Cascade) and the closure expansion fails — driver error during the transitive dependency walk, cancelled context, or a backend query failure while expanding the cascade.","commonSituations":"Deep cascade graphs hitting context timeouts; connection loss mid-closure; corrupted dependency edges stalling expansion; schema drift on dependency tables.","solutions":["Inspect the wrapped error from ResolveDeletionSetInTx for the real cause","Retry with a fresh transaction; nothing was written, so retry is safe","For deep cascades, raise the context timeout or delete the graph in stages","Verify dependency-table integrity (orphaned/looping edges) if failures recur on the same ids","Check migrations are current on the backend"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// nothing to validate client-side; ensure ctx budget fits the cascade size\nif err := ctx.Err(); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := store.Delete(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"delete: \") {\n    // ResolveDeletionSetInTx failed before any write; safe to retry whole op\n    return retryWithFreshTx(req)\n}","preventionTips":["Budget generous timeouts for deep cascades","Use DryRun to precompute cascade size before committing","Keep dependency edges clean (no orphaned rows) so closure walks stay cheap","Retry freely: the set is resolved before any write, so failures leave no partial state"],"tags":["database","delete","cascade","wrapper-error"],"backgroundTag":"db-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}