{"record":{"id":"57d7ab09c89135ef","repo":"gastownhall/beads","slug":"cascade-traversal-discovered-over-d-issues-abort","errorCode":null,"errorMessage":"cascade traversal discovered over %d issues; aborting to prevent runaway deletion","messagePattern":"cascade traversal discovered over (.+?) issues; aborting to prevent runaway deletion","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/delete.go","lineNumber":417,"sourceCode":"}\n\n// findAllDependentsRecursiveInTx finds all issues that depend on the given\n// issues, recursively. Uses batched IN-clause queries. Traversal is capped\n// at maxRecursiveResults total discovered IDs.\n//\n//nolint:gosec // G201: inClause contains only ? placeholders\nfunc FindAllDependentsInTx(ctx context.Context, tx DBTX, ids []string) (map[string]bool, error) {\n\tresult := make(map[string]bool)\n\tfor _, id := range ids {\n\t\tresult[id] = true\n\t}\n\n\ttoProcess := make([]string, len(ids))\n\tcopy(toProcess, ids)\n\n\tfor len(toProcess) > 0 {\n\t\tif len(result) > maxRecursiveResults {\n\t\t\treturn nil, fmt.Errorf(\"cascade traversal discovered over %d issues; aborting to prevent runaway deletion\", maxRecursiveResults)\n\t\t}\n\t\tbatchEnd := deleteBatchSize\n\t\tif batchEnd > len(toProcess) {\n\t\t\tbatchEnd = len(toProcess)\n\t\t}\n\t\tbatch := toProcess[:batchEnd]\n\t\ttoProcess = toProcess[batchEnd:]\n\n\t\tinClause, args := buildSQLInClause(batch)\n\t\tfor _, depTable := range []string{\"dependencies\", \"wisp_dependencies\"} {\n\t\t\trows, err := tx.QueryContext(ctx,\n\t\t\t\tfmt.Sprintf(`SELECT issue_id FROM %s WHERE %s`, depTable, depTargetIn(\"\", inClause)),\n\t\t\t\targs...)\n\t\t\tif err != nil {\n\t\t\t\tif optionalBlockedTable(depTable) && isTableNotExistError(err) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"query dependents for batch from %s: %w\", depTable, err)","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/delete.go#L399-L435","documentation":"FindAllDependentsInTx performs a breadth-first traversal of the dependency graph to find everything that would be cascade-deleted. If the traversal discovers more than maxRecursiveResults distinct issues, it aborts with this error to prevent a runaway (possibly cyclic or hub-dependent) cascade from deleting a huge portion of the database.","triggerScenarios":"ResolveDeletionSetInTx invoked with --cascade on an issue that transitively depends on more than maxRecursiveResults issues — e.g. deleting a root blocking hundreds of chained beads, or a dependency cycle inflating the reachable set.","commonSituations":"Deleting a top-level epic/milestone whose entire subtree exceeds the cap; accidental cycles in dependencies making the reachable set appear unbounded; importing a dependency graph with a hub issue everything depends on.","solutions":["Delete in smaller pieces — delete leaf dependents first instead of one big cascade","Inspect the dependency graph (bd dep tree / bd blocked) to find the hub or cycle and break it","If the set is legitimately large and intended, delete in batches scoped by explicit ID lists","Report/fix the cycle if one exists; cycles should not occur in a healthy DAG"],"exampleFix":"// before\nbd delete bd-1 --cascade  // aborts: >maxRecursiveResults\n// after — prune from the leaves\nbd dep tree bd-1          # inspect scope\nbd delete bd-101 bd-102 --cascade\nbd delete bd-1 --cascade","handlingStrategy":"validation","validationCode":"// pre-check cascade size before attempting delete\nfunc cascadeSize(ctx, tx, ids) int {\n\t// count reachable dependents via bd dep tree or iterative queries\n}\n// if cascadeSize > maxRecursiveResults { delete in smaller batches instead }","typeGuard":null,"tryCatchPattern":"_, err := DeleteIssuesInTx(ctx, tx, ids, WithCascade())\nif err != nil && strings.Contains(err.Error(), \"aborting to prevent runaway deletion\") {\n\t// fall back to scoped deletes\n\treturn deleteInChunks(ctx, ids)\n}\nreturn err","preventionTips":["Inspect bd dep tree before --cascade on hub/root issues","Find and fix dependency cycles in the graph","Delete large subtrees incrementally from the leaves","Keep the dependency graph a healthy DAG"],"tags":["cascade","dependency-graph","safety-limit","delete"],"backgroundTag":"cascade-limit-exceeded","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}