{"record":{"id":"bc952b3626a1ade9","repo":"gastownhall/beads","slug":"failed-to-check-for-dependency-cycle-w","errorCode":null,"errorMessage":"failed to check for dependency cycle: %w","messagePattern":"failed to check for dependency cycle: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependencies.go","lineNumber":450,"sourceCode":"\t\t  )\n\t`, sourceTable, targetTable), source, target)\n\treturn err\n}\n\n// CheckDependencyCycleInTx rejects self-dependencies and cycles across the\n// combined blocks, conditional-blocks, and parent-child graph before insert.\n// The caller may pass a restricted depTables list for a known storage bucket;\n// nil uses all dependency tables.\nfunc CheckDependencyCycleInTx(ctx context.Context, tx DBTX, dep *types.Dependency, depTables []string) error {\n\tif dep.IssueID == dep.DependsOnID {\n\t\treturn fmt.Errorf(\"%w: %s cannot depend on itself\", domain.ErrSelfDependency, dep.IssueID)\n\t}\n\tif !types.IsSchedulingEdge(dep.Type) {\n\t\treturn nil\n\t}\n\twouldCycle, err := WouldCreateSchedulingCycleInTx(ctx, tx, dep.IssueID, dep.DependsOnID, depTables)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to check for dependency cycle: %w\", err)\n\t}\n\tif wouldCycle {\n\t\treturn domain.ErrDependencyCycle\n\t}\n\treturn nil\n}\n\n// WouldCreateSchedulingCycleInTx reports whether adding issueID -> dependsOnID\n// would close a cycle in the combined scheduling graph. It is shared by the\n// classic and domain storage stacks so both traverse the same dependency types\n// and typed target columns.\nfunc WouldCreateSchedulingCycleInTx(ctx context.Context, tx DBTX, issueID, dependsOnID string, depTables []string) (bool, error) {\n\tif len(depTables) == 0 {\n\t\tdepTables = cycleDetectionTables()\n\t}\n\tvar reachable int\n\tquery := cycleReachabilityQuery(depTables)\n\tif err := tx.QueryRowContext(ctx, query, dependsOnID, issueID).Scan(&reachable); err != nil {","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependencies.go#L432-L468","documentation":"Wraps an infrastructure error from WouldCreateSchedulingCycleInTx while CheckDependencyCycleInTx is determining whether the new edge would form a cycle. This is not a detected cycle (that returns domain.ErrDependencyCycle); it means the cycle-detection queries themselves failed, so the check could not be performed.","triggerScenarios":"CheckDependencyCycleInTx called with a scheduling-edge dependency where the underlying graph traversal queries in WouldCreateSchedulingCycleInTx error out — DB unreachable, transaction aborted, invalid depTables list, or corrupt rows in the dependency tables.","commonSituations":"Transient database failures during a dep-add; wrong depTables argument filtering to a nonexistent bucket; migration drift leaving dependency rows referencing missing issues.","solutions":["Inspect the wrapped cause (%w) for the real SQL failure and fix that","Verify the depTables argument names valid storage buckets (or pass nil for all tables)","Retry once the database is healthy; the check is read-only so a retry is safe","Repair dangling dependency rows if traversal errors point at missing referenced issues"],"exampleFix":"// before\nif err := issueops.CheckDependencyCycleInTx(ctx, tx, dep, []string{\"dep_links\"}); err != nil {\n\treturn err\n}\n// after: use the default tables (nil = all dependency tables)\nif err := issueops.CheckDependencyCycleInTx(ctx, tx, dep, nil); err != nil {\n\tif errors.Is(err, domain.ErrDependencyCycle) {\n\t\treturn err\n\t}\n\treturn fmt.Errorf(\"cycle check infra failure: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// check both endpoints exist and tables are valid before cycle check\nif !exists(ctx, db, dep.IssueID) || !exists(ctx, db, dep.DependsOnID) {\n\treturn errors.New(\"dependency endpoint missing\")\n}\nif depTables != nil {\n\tfor _, t := range depTables {\n\t\tif !validDepTable(t) { return fmt.Errorf(\"unknown dep table %q\", t) }\n\t}\n}","typeGuard":"func isCycleCheckInfraFailure(err error) bool {\n\treturn err != nil &&\n\t\t!errors.Is(err, domain.ErrDependencyCycle) &&\n\t\tstrings.Contains(err.Error(), \"failed to check for dependency cycle\")\n}","tryCatchPattern":"err := issueops.CheckDependencyCycleInTx(ctx, tx, dep, nil)\nswitch {\ncase errors.Is(err, domain.ErrDependencyCycle):\n\treturn err // genuine cycle\ncase err != nil:\n\treturn retryWithBackoff(op) // infra failure, read-only check is safe to retry\n}","preventionTips":["Pass nil depTables unless you know the bucket, to avoid invalid table lists","Treat this wrap as retryable — it is never a real cycle result","Monitor DB health; this surfaces transient query failures","Repair dangling dependency rows that can break traversal"],"tags":["database","cycle-detection","transaction"],"backgroundTag":"cycle-check-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}