gastownhall/beads · error

descendants: query: %w

Error message

descendants: query: %w

What it means

GetDescendants wraps an error from r.runner.QueryContext executing the generated recursive CTE that walks parent-child edges (and dotted-ID fallbacks) across the issues and wisps tables. This is the raw SQL execution failure — syntax, engine, connection, or schema errors from the Dolt/MySQL backend — surfaced after the query was already assembled successfully.

Source

Thrown at internal/storage/domain/db/issue_descendants.go:81

	var wispArgs []any
	if walkWisps {
		wispWhereClauses, wispArgs, err = buildIssueFilterClauses("", levelFilter, wispsFilterTables)
		if err != nil {
			return nil, fmt.Errorf("descendants: wisps filter: %w", err)
		}
	}

	issuePred := buildDescendantsPred("issues", "i", "issue_matches", issueWhereClauses, issueArgs)
	var wispPred predBundle
	if walkWisps {
		wispPred = buildDescendantsPred("wisps", "w", "wisp_matches", wispWhereClauses, wispArgs)
	}

	cte, allArgs := buildDescendantsCTE(rootID, walkWisps, issuePred, wispPred)

	rows, err := r.runner.QueryContext(ctx, cte, allArgs...)
	if err != nil {
		return nil, fmt.Errorf("descendants: query: %w", err)
	}
	page, err := scanIDSrcPage(rows)
	if err != nil {
		return nil, fmt.Errorf("descendants: %w", err)
	}

	issuesByID, err := r.fetchIssuesByIDs(ctx, page.issueIDs, issuesFilterTables, filter)
	if err != nil {
		return nil, fmt.Errorf("descendants: hydrate issues: %w", err)
	}

	var wispsByID map[string]*types.Issue
	if len(page.wispIDs) > 0 {
		wispsByID, err = r.fetchIssuesByIDs(ctx, page.wispIDs, wispsFilterTables, filter)
		if err != nil && !dberrors.IsTableNotExist(err) {
			return nil, fmt.Errorf("descendants: hydrate wisps: %w", err)
		}
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error; if it mentions "unable to find field with index", upgrade/downgrade Dolt to a version without the recursive-CTE analyzer bug
  2. Run bd doctor to verify schema completeness (issues, wisps, dependencies, wisp_dependencies all present and consistent)
  3. Increase the context timeout or check cancellation if the error is context deadline/canceled
  4. Retry on transient connection errors; check Dolt server logs for the failing query

Example fix

// before: bare context that expires mid-walk
ctx := context.Background()
issues, err := repo.GetDescendants(ctx, root, filter)
// after: give deep hierarchy walks room
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
issues, err := repo.GetDescendants(ctx, root, filter)
Defensive patterns

Strategy: retry

Try / catch

issues, err := repo.GetDescendants(ctx, rootID, filter)
var netErr net.Error
if err != nil && (errors.Is(err, context.DeadlineExceeded) || errors.As(err, &netErr)) {
    // retry with a longer deadline
}

Prevention

When it happens

Trigger: Calling GetDescendants when the WITH RECURSIVE descendants query fails server-side: engine analyzer bugs (e.g. the documented dolt 2.1.6 "unable to find field with index N" issue), missing tables/columns, connection drop, or cancellation of ctx mid-query.

Common situations: Running an older or newer Dolt engine with a known recursive-CTE analyzer bug; a database migrated from the pre-wisps schema missing wisp tables the CTE references; long-running walk killed by context timeout.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


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