{"record":{"id":"2120d00d9780dc07","repo":"gastownhall/beads","slug":"db-dependencysqlrepository-cyclethroughedges-w","errorCode":null,"errorMessage":"db: DependencySQLRepository.CycleThroughEdges: %w","messagePattern":"db: DependencySQLRepository\\.CycleThroughEdges: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/dependency.go","lineNumber":944,"sourceCode":"\tmaxDepth := opts.MaxDepth\n\tif maxDepth <= 0 {\n\t\tmaxDepth = 50\n\t}\n\treverse := opts.Direction == domain.DepDirectionIn\n\tout, err := issueops.GetDependencyTreeInTx(ctx, r.runner, rootID, maxDepth, opts.ShowAllPaths, reverse)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: DependencySQLRepository.GetTree: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (r *dependencySQLRepositoryImpl) CycleThroughEdges(ctx context.Context, edges [][2]string) (string, error) {\n\tif len(edges) == 0 {\n\t\treturn \"\", nil\n\t}\n\tgraph := make(map[string][]string)\n\tif err := issueops.AppendSchedulingGraphInTx(ctx, r.runner, []string{\"dependencies\"}, graph); err != nil {\n\t\treturn \"\", fmt.Errorf(\"db: DependencySQLRepository.CycleThroughEdges: %w\", err)\n\t}\n\tif err := issueops.AppendSchedulingGraphInTx(ctx, r.runner, []string{\"wisp_dependencies\"}, graph); err != nil && !dberrors.IsTableNotExist(err) {\n\t\treturn \"\", fmt.Errorf(\"db: DependencySQLRepository.CycleThroughEdges (wisps): %w\", err)\n\t}\n\treturn issueops.CycleThroughEdgesInGraph(graph, edges), nil\n}\n\n// WispSourceIDs classifies a batch of ids by plane in one scoped query. It is\n// the proxied twin of the in-tx probe the store-backed dependency editor runs,\n// and shares its implementation so the two answer the same question — down to\n// treating a missing wisps table as \"no wisps\" rather than an error.\nfunc (r *dependencySQLRepositoryImpl) WispSourceIDs(ctx context.Context, ids []string) (map[string]struct{}, error) {\n\tset, err := issueops.WispIDSetInTx(ctx, r.runner, ids)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: DependencySQLRepository.WispSourceIDs: %w\", err)\n\t}\n\treturn set, nil\n}","sourceCodeStart":926,"sourceCodeEnd":962,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/dependency.go#L926-L962","documentation":"CycleThroughEdges builds a scheduling graph from the dependencies table via AppendSchedulingGraphInTx, then checks whether the given edges would close a cycle. This wrapper means loading the core dependencies table into the graph failed. Only non-empty edge lists reach the query; empty input returns \"\", nil without touching the database.","triggerScenarios":"Calling CycleThroughEdges(ctx, edges) with at least one edge pair, where AppendSchedulingGraphInTx for the \"dependencies\" table fails: table missing/corrupt, connection error, or context cancellation.","commonSituations":"Pre-flight cycle checks before adding an edge, run against a stopped Dolt server; missing dependencies table after a bad migration; deadline exceeded on large graphs.","solutions":["Unwrap to see the root SQL/driver error from AppendSchedulingGraphInTx.","Verify the dependencies table exists and the schema is migrated.","Check database connectivity and retry.","Increase context timeout for large dependency graphs."],"exampleFix":"// before\nedge, err := repo.CycleThroughEdges(ctx, edges) // bare ctx, server down\n// after: ensure server reachable first\nif err := db.PingContext(ctx); err != nil { return err }\nedge, err := repo.CycleThroughEdges(ctx, edges)","handlingStrategy":"validation","validationCode":"if len(edges) == 0 {\n    return nil // library returns \"\", nil without DB access for empty input\n}\nif err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"db unreachable before cycle check: %w\", err)\n}","typeGuard":"func hasEdges(edges [][2]string) bool { return len(edges) > 0 }","tryCatchPattern":"edge, err := repo.CycleThroughEdges(ctx, edges)\nif err != nil {\n    if dberrors.IsTableNotExist(errors.Unwrap(err)) {\n        // missing dependencies table: treat as no graph\n        return \"\", nil\n    }\n    return fmt.Errorf(\"cycle check: %w\", err)\n}","preventionTips":["Skip the call for empty edge lists — it is a free no-op.","Ensure the dependencies table exists (migrations) before pre-flight cycle checks.","Use a bounded context; graph loading scales with total edge count."],"tags":["database","cycle-detection","graph","wrapper"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}