gastownhall/beads · error

get parent descendants: %w

Error message

get parent descendants: %w

What it means

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.

Source

Thrown at internal/storage/domain/db/ready_work.go:42

}

// buildReadyWorkPredicates computes the ID sets the ready-work WHERE clause
// needs (children of deferred parents, parent descendants), then delegates
// the clause text to sqlbuild so both stacks share ready semantics. Unlike
// the classic stack, ORDER BY and LIMIT are applied at the UNION outer query.
func (r *issueSQLRepositoryImpl) buildReadyWorkPredicates(ctx context.Context, filter types.WorkFilter, tables filterTables) (*readyWorkPredicates, error) {
	var inputs sqlbuild.ReadyWorkWhereInputs
	if !filter.IncludeDeferred {
		deferredChildIDs, dcErr := r.getChildrenOfDeferredParents(ctx)
		if dcErr != nil {
			return nil, fmt.Errorf("get ready work: compute deferred parent children: %w", dcErr)
		}
		inputs.DeferredChildIDs = deferredChildIDs
	}
	if filter.ParentID != nil {
		descendantIDs, descErr := r.getDescendantIDs(ctx, *filter.ParentID, 0)
		if descErr != nil {
			return nil, fmt.Errorf("get parent descendants: %w", descErr)
		}
		inputs.ParentDescendantIDs = descendantIDs
	}

	whereSQL, args, err := sqlbuild.BuildReadyWorkWhere(filter, tables, inputs)
	if err != nil {
		return nil, err
	}
	return &readyWorkPredicates{whereSQL: whereSQL, args: args}, nil
}

type deferredParentEdge struct {
	depTable, issueTable, targetCol string
}

var deferredParentEdges = []deferredParentEdge{
	{"dependencies", "issues", "depends_on_issue_id"},
	{"dependencies", "wisps", "depends_on_wisp_id"},

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the inner error from getDescendantIDs for the failing table or SQL issue
  2. Verify the ParentID exists and its dependency edges are intact
  3. Confirm dependencies/wisp_dependencies tables exist for this deployment mode
  4. If graphs are deep, raise the traversal max depth or restructure the hierarchy
Defensive patterns

Strategy: validation

Validate before calling

// confirm the parent exists before scoping ready work to it
var exists int
err := db.QueryRow("SELECT 1 FROM issues WHERE id = ?", parentID).Scan(&exists)
if errors.Is(err, sql.ErrNoRows) { return fmt.Errorf("parent %s not found", parentID) }

Type guard

func isParentDescendantsError(err error) bool {
	return err != nil && strings.Contains(err.Error(), "get parent descendants")
}

Try / catch

ready, err := repo.GetReadyWork(ctx, filter)
if isParentDescendantsError(err) {
	// drop the ParentID scope or retry after checking dependency tables
	filter.ParentID = nil
	ready, err = repo.GetReadyWork(ctx, filter)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/b8c0fc25588c6d80. Report an issue: GitHub.