{"record":{"id":"36b42c777f8c820e","repo":"gastownhall/beads","slug":"get-dependents-fetch-issues-w","errorCode":null,"errorMessage":"get dependents: fetch issues: %w","messagePattern":"get dependents: fetch issues: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependencies.go","lineNumber":1200,"sourceCode":"\t\t}\n\t\t_ = rows.Close()\n\t\tif err := rows.Err(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"get dependents: rows from %s: %w\", depTable, err)\n\t\t}\n\t}\n\n\tif len(deps) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Fetch all dependent issues.\n\tids := make([]string, len(deps))\n\tfor i, d := range deps {\n\t\tids[i] = d.depID\n\t}\n\tissues, err := GetIssuesByIDsInTx(ctx, tx, ids, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get dependents: fetch issues: %w\", err)\n\t}\n\tissueMap := make(map[string]*types.Issue, len(issues))\n\tfor _, iss := range issues {\n\t\tissueMap[iss.ID] = iss\n\t}\n\n\tvar results []*types.IssueWithDependencyMetadata\n\tfor _, d := range deps {\n\t\tissue, ok := issueMap[d.depID]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tresults = append(results, &types.IssueWithDependencyMetadata{\n\t\t\tIssue:          *issue,\n\t\t\tDependencyType: types.DependencyType(d.depType),\n\t\t})\n\t}\n\treturn results, nil","sourceCodeStart":1182,"sourceCodeEnd":1218,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependencies.go#L1182-L1218","documentation":"GetDependentsWithMetadataInTx wraps any error from GetIssuesByIDsInTx when loading the issue records for the dependent IDs it just collected. The dependency edges read fine; hydrating the dependent issues themselves failed, with the underlying cause preserved via %w.","triggerScenarios":"GetDependentsWithMetadataInTx found dependent rows, then the batched SELECT via GetIssuesByIDsInTx over those issue IDs failed — query error, scan mismatch, rows error, or label-hydration error inside that helper.","commonSituations":"Orphaned dependency rows referencing IDs missing from issues/wisp_issues combined with strict schema checks; very large fan-out exceeding parameter limits; transient DB failure; schema drift in the issues tables.","solutions":["Unwrap the %w chain to the GetIssuesByIDsInTx sub-error and address that specific failure.","Check for orphan rows: dependent IDs that don't exist in either issue table (the code skips missing ones, but fetch errors still propagate).","Verify the issues/wisp_issues schema matches what ScanIssueFrom expects.","Retry on a fresh transaction if the cause is transient."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify dependent IDs resolve to real issues before hydration\nids, err := collectDependentIDs(ctx, tx, issueID)\nif err != nil { return err }\nfor _, id := range ids {\n    if !issueExists(ctx, tx, id) { log.Printf(\"orphan dependent row: %s\", id) }\n}","typeGuard":"func isHydrationErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"fetch issues\")\n}","tryCatchPattern":"deps, err := GetDependentsWithMetadataInTx(ctx, tx, issueID)\nif err != nil {\n    if isHydrationErr(err) {\n        log.Printf(\"dependent issue hydration failed: %v\", errors.Unwrap(err))\n    }\n    return err\n}","preventionTips":["Use FK constraints (or periodic orphan sweeps) between dependency tables and issue tables.","Unwrap the error to the GetIssuesByIDsInTx cause before diagnosing.","Keep issue-table schema aligned with ScanIssueFrom expectations.","Limit fan-out size to stay within driver parameter limits."],"tags":["database","sql","go","hydration"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}