{"record":{"id":"b8c0fc25588c6d80","repo":"gastownhall/beads","slug":"get-parent-descendants-w","errorCode":null,"errorMessage":"get parent descendants: %w","messagePattern":"get parent descendants: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/ready_work.go","lineNumber":42,"sourceCode":"}\n\n// buildReadyWorkPredicates computes the ID sets the ready-work WHERE clause\n// needs (children of deferred parents, parent descendants), then delegates\n// the clause text to sqlbuild so both stacks share ready semantics. Unlike\n// the classic stack, ORDER BY and LIMIT are applied at the UNION outer query.\nfunc (r *issueSQLRepositoryImpl) buildReadyWorkPredicates(ctx context.Context, filter types.WorkFilter, tables filterTables) (*readyWorkPredicates, error) {\n\tvar inputs sqlbuild.ReadyWorkWhereInputs\n\tif !filter.IncludeDeferred {\n\t\tdeferredChildIDs, dcErr := r.getChildrenOfDeferredParents(ctx)\n\t\tif dcErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"get ready work: compute deferred parent children: %w\", dcErr)\n\t\t}\n\t\tinputs.DeferredChildIDs = deferredChildIDs\n\t}\n\tif filter.ParentID != nil {\n\t\tdescendantIDs, descErr := r.getDescendantIDs(ctx, *filter.ParentID, 0)\n\t\tif descErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"get parent descendants: %w\", descErr)\n\t\t}\n\t\tinputs.ParentDescendantIDs = descendantIDs\n\t}\n\n\twhereSQL, args, err := sqlbuild.BuildReadyWorkWhere(filter, tables, inputs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &readyWorkPredicates{whereSQL: whereSQL, args: args}, nil\n}\n\ntype deferredParentEdge struct {\n\tdepTable, issueTable, targetCol string\n}\n\nvar deferredParentEdges = []deferredParentEdge{\n\t{\"dependencies\", \"issues\", \"depends_on_issue_id\"},\n\t{\"dependencies\", \"wisps\", \"depends_on_wisp_id\"},","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/ready_work.go#L24-L60","documentation":"Wraps failures from getDescendantIDs while resolving the descendants of filter.ParentID during ready-work computation. The descendant lookup runs a recursive CTE over dependency edges; any failure there makes parent-scoped ready work unanswerable. The chain also includes the traversal max-depth guard further down.","triggerScenarios":"Calling GetReadyWork with filter.ParentID set while the recursive descendant query fails: connection error, missing dependencies/wisp_dependencies tables (after the wisp fallback also fails), or a scan/rows error inside the CTE result.","commonSituations":"Passing a ParentID whose dependency graph sits in tables missing from the current deployment; very deep graphs hitting max depth; transient DB errors during recursive traversal.","solutions":["Check the inner error from getDescendantIDs for the failing table or SQL issue","Verify the ParentID exists and its dependency edges are intact","Confirm dependencies/wisp_dependencies tables exist for this deployment mode","If graphs are deep, raise the traversal max depth or restructure the hierarchy"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// confirm the parent exists before scoping ready work to it\nvar exists int\nerr := db.QueryRow(\"SELECT 1 FROM issues WHERE id = ?\", parentID).Scan(&exists)\nif errors.Is(err, sql.ErrNoRows) { return fmt.Errorf(\"parent %s not found\", parentID) }","typeGuard":"func isParentDescendantsError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"get parent descendants\")\n}","tryCatchPattern":"ready, err := repo.GetReadyWork(ctx, filter)\nif isParentDescendantsError(err) {\n\t// drop the ParentID scope or retry after checking dependency tables\n\tfilter.ParentID = nil\n\tready, err = repo.GetReadyWork(ctx, filter)\n}","preventionTips":["Validate ParentID exists before filtering ready work by it","Keep dependencies/wisp_dependencies tables present and consistent","Keep hierarchies shallow or raise the traversal max depth","Retry transient failures around recursive queries"],"tags":["database","ready-work","recursion","hierarchy"],"backgroundTag":"descendant-traversal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}