{"record":{"id":"84a7857a35933f67","repo":"gastownhall/beads","slug":"delete-cascade-expansion-w","errorCode":null,"errorMessage":"delete: cascade expansion: %w","messagePattern":"delete: cascade expansion: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":79,"sourceCode":"}\n\nfunc (u *issueUseCaseImpl) PreviewDeleteWisp(ctx context.Context, ids []string) (DeletePreview, error) {\n\treturn u.previewDelete(ctx, ids)\n}\n\nfunc (u *issueUseCaseImpl) deleteMany(ctx context.Context, params DeleteIssuesParams, actor string) (DeleteIssuesResult, error) {\n\tif len(params.IDs) == 0 {\n\t\treturn DeleteIssuesResult{}, nil\n\t}\n\n\tresult := DeleteIssuesResult{}\n\n\tallIDs := params.IDs\n\tswitch {\n\tcase params.Cascade:\n\t\texpanded, err := u.issueRepo.FindAllDependents(ctx, params.IDs)\n\t\tif err != nil {\n\t\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"delete: cascade expansion: %w\", err)\n\t\t}\n\t\tallIDs = expanded\n\tcase params.EnforceCascadePolicy:\n\t\t// Embedded-parity dependent handling (see DeleteIssuesParams): without\n\t\t// Cascade, an external dependent either blocks the delete (no Force) or\n\t\t// is orphaned (Force), never silently swept.\n\t\texternalBySource, err := u.externalDependents(ctx, params.IDs)\n\t\tif err != nil {\n\t\t\treturn DeleteIssuesResult{}, err\n\t\t}\n\t\tif params.Force {\n\t\t\torphanSet := map[string]bool{}\n\t\t\tfor _, deps := range externalBySource {\n\t\t\t\tfor _, dep := range deps {\n\t\t\t\t\torphanSet[dep] = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.OrphanedIssues = sortedStringSet(orphanSet)","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L61-L97","documentation":"deleteMany wraps errors from issueRepo.FindAllDependents when expanding the deletion set in cascade mode. The 'delete: cascade expansion:' prefix identifies the dependent-graph traversal as the failing step, with the repository error preserved via %w. Deletion is aborted before anything is removed.","triggerScenarios":"Calling DeleteIssue/DeleteWisp/DeleteIssues/DeleteWisps with Cascade=true when FindAllDependents fails — DB connection failure, SQL error during the dependency-graph recursive query, or storage unavailable.","commonSituations":"Cascading deletes during large dependency graphs while Dolt restarts; schema drift breaking the dependents query; concurrent modifications locking rows during expansion.","solutions":["Unwrap the error chain to find the underlying FindAllDependents failure","Confirm the Dolt database is reachable and healthy","Retry the delete; cascade expansion is read-only and safe to re-run","If schema errors persist, run beads schema migration/upgrade"],"exampleFix":"// before\nres, err := uc.DeleteIssues(ctx, ids, actor)\nif err != nil { return err }\n// after\nif err != nil {\n\tif strings.Contains(err.Error(), \"cascade expansion\") {\n\t\t// storage read failed; nothing was deleted — safe to retry\n\t\treturn retryDelete(ctx, ids)\n\t}\n\treturn err\n}","handlingStrategy":"retry","validationCode":"// pre-check storage before cascade delete\nif err := pingDolt(ctx); err != nil {\n\treturn fmt.Errorf(\"cannot cascade delete now: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"res, err := uc.DeleteIssues(ctx, ids, actor)\nif err != nil {\n\tif strings.Contains(err.Error(), \"cascade expansion\") {\n\t\t// read-only phase failed; nothing deleted — safe to retry\n\t\treturn retryWithBackoff(func() error { _, err := uc.DeleteIssues(ctx, ids, actor); return err })\n\t}\n\treturn err\n}","preventionTips":["Confirm Dolt health before large cascade deletes","Retry cascade deletes with exponential backoff","Keep dependency-graph tables migrated to the current schema"],"tags":["go","delete","cascade","dependency-graph","wrapped-error"],"backgroundTag":"storage-operation-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}