gastownhall/beads · error

iter dependents %s: %w

Error message

iter dependents %s: %w

What it means

collectDependents wraps any error from IterDependents in "iter dependents %s: %w", annotating which issue's dependents failed to iterate. BuildIssueDetails calls this while assembling detail payloads, so a storage/iterator failure surfaces with the offending id as context.

Source

Thrown at internal/workapi/detail.go:203

			Priority:  item.Issue.Priority,
			Title:     item.Issue.Title,
		},
		DependencyType: item.DependencyType,
	}
}

// collectDependents streams the dependents and keeps only the
// identity-and-shape fields of each.
//
// be-4d36f2: hub beads with thousands of dependents made `bd show --json
// <hub>` allocate 5-13 GB marshaling full Issue records. The shallow shape
// preserves what callers consume (id, status, type, priority, title) and
// drops the free-form text; streaming keeps the full rows from piling up
// while we do it.
func collectDependents(ctx context.Context, src DetailSource, id string, isWisp bool) ([]*types.IssueWithDependencyMetadata, error) {
	iter, err := src.IterDependents(ctx, id, isWisp)
	if err != nil {
		return nil, fmt.Errorf("iter dependents %s: %w", id, err)
	}
	defer iter.Close() //nolint:errcheck // read-only iterator

	var out []*types.IssueWithDependencyMetadata
	for iter.Next(ctx) {
		item := iter.Value()
		if item == nil {
			continue
		}
		out = append(out, shallowDep(item))
	}
	if err := iter.Err(); err != nil {
		return nil, fmt.Errorf("iter dependents %s: %w", id, err)
	}
	return out, nil
}

func collectComments(ctx context.Context, src DetailSource, id string, isWisp bool) ([]*types.Comment, error) {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped (%w) inner error for the root storage cause
  2. Retry the detail build with a fresh context if it was cancellation/deadline related
  3. Verify the DetailSource backend is healthy (connectivity, schema) before rebuilding

Example fix

// before
ctx := context.Background()
details, err := api.BuildIssueDetails(ctx, ids)
// after
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
details, err := api.BuildIssueDetails(ctx, ids)
if err != nil {
    var target *storage.Err
    if errors.As(err, &target) { /* reconnect / retry backend */ }
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: ensure the source backend is reachable before building details
if err := src.Ping(ctx); err != nil { return fmt.Errorf("detail source unavailable: %w", err) }

Try / catch

details, err := api.BuildIssueDetails(ctx, ids)
if err != nil && strings.Contains(err.Error(), "iter dependents") {
    return retryWithBackoff(ctx, 3, func() error {
        var rerr error
        details, rerr = api.BuildIssueDetails(ctx, ids)
        return rerr
    })
}

Prevention

When it happens

Trigger: src.IterDependents returning an error for the given id (storage failure, closed backend, context cancellation during dependency iteration) inside BuildIssueDetails.

Common situations: Database connection dropped mid-detail-build; context deadline exceeded while iterating many dependents; storage seam misconfigured for the wisp/issue table being queried.

Related errors


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