{"record":{"id":"4d4115f6c30a5413","repo":"gastownhall/beads","slug":"db-dependencysqlrepository-detectcyclereport-w","errorCode":null,"errorMessage":"db: DependencySQLRepository.DetectCycleReport: %w","messagePattern":"db: DependencySQLRepository\\.DetectCycleReport: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/dependency.go","lineNumber":892,"sourceCode":"\tblocked, blockers, err := issueops.IsBlockedInTx(ctx, r.runner, issueID)\n\tif err != nil {\n\t\treturn false, nil, fmt.Errorf(\"db: DependencySQLRepository.IsBlocked %s: %w\", issueID, err)\n\t}\n\treturn blocked, blockers, nil\n}\n\nfunc (r *dependencySQLRepositoryImpl) DetectCycles(ctx context.Context) ([][]*types.Issue, error) {\n\tout, err := issueops.DetectCyclesInTx(ctx, r.runner)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: DependencySQLRepository.DetectCycles: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (r *dependencySQLRepositoryImpl) DetectCycleReport(ctx context.Context) (publicops.CycleReport, error) {\n\tout, err := issueops.DetectCycleReportInTx(ctx, r.runner)\n\tif err != nil {\n\t\treturn publicops.CycleReport{}, fmt.Errorf(\"db: DependencySQLRepository.DetectCycleReport: %w\", err)\n\t}\n\treturn out, nil\n}\n\n// WalkDependencyTree runs the SHARED walk body, unwrapped.\n//\n// It does NOT wrap the error the way its siblings above do, and that is the one\n// thing to keep when editing it: the body publishes issueops.ErrValidation,\n// storage.ErrNotFound and *issueops.ErrTooManyRows as the role's own vocabulary,\n// and every one of those is classified by errors.Is/errors.As at both front\n// doors and in the HTTP problem mapping. A `fmt.Errorf(\"db: ...: %w\")` would keep\n// them matchable but would also put this repository's name into the message a\n// user reads, which the direct route never does for the same refusal.\nfunc (r *dependencySQLRepositoryImpl) WalkDependencyTree(ctx context.Context, req publicops.WalkTreeRequest) (publicops.TreeResult, error) {\n\treturn issueops.WalkDependencyTreeInTx(ctx, r.runner, req)\n}\n\n// CountEdges runs the SHARED edge-count body, unwrapped for","sourceCodeStart":874,"sourceCodeEnd":910,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/dependency.go#L874-L910","documentation":"DetectCycleReport calls issueops.DetectCycleReportInTx and wraps its failure with repository context. DetectCycleReportInTx builds a richer cycle report than DetectCycles; failure here means the underlying report queries/graph load errored, not that cycles exist (cycles are reported in the returned CycleReport value).","triggerScenarios":"Calling DetectCycleReport(ctx) when the underlying report generation fails: SQL errors reading dependency data, connection drops, or context cancellation inside DetectCycleReportInTx.","commonSituations":"Integrity/doctor reports against a stopped or corrupted Dolt database; schema drift after a version upgrade; timeouts on very large dependency sets.","solutions":["Unwrap the error to expose the root cause from DetectCycleReportInTx.","Verify database availability and schema migrations.","Retry with a longer context timeout.","Fall back to DetectCycles if only cycle membership is needed."],"exampleFix":"// before\nreport, err := repo.DetectCycleReport(ctx)\n// after: tolerate failure and fall back\nreport, err := repo.DetectCycleReport(ctx)\nif err != nil {\n    cycles, cerr := repo.DetectCycles(ctx)\n    if cerr != nil { return fmt.Errorf(\"cycle detection failed: %w\", err) }\n}","handlingStrategy":"fallback","validationCode":"if err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"db unavailable before DetectCycleReport: %w\", err)\n}","typeGuard":"func isTransientDBErr(err error) bool {\n    return errors.Is(err, driver.ErrBadConn) || errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"report, err := repo.DetectCycleReport(ctx)\nif err != nil {\n    // fall back to plain cycle detection\n    cycles, cerr := repo.DetectCycles(ctx)\n    if cerr != nil { return fmt.Errorf(\"cycle report: %w\", err) }\n    _ = cycles\n}","preventionTips":["Fall back to DetectCycles when the richer report fails.","Schedule integrity reports during low database load.","Retry transient errors with exponential backoff."],"tags":["database","cycle-detection","report","wrapper"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}