gastownhall/beads · error

searching local issues for Linear milestone %s: %w

Error message

searching local issues for Linear milestone %s: %w

What it means

findLinearMilestoneEpic falls back to a full SearchIssues scan when the milestone epic isn't found by external ref, matching issues by embedded milestone ID metadata. If that search fails, the error wraps the storage failure with the milestone ID. This is the slow-path dedup lookup during Linear milestone sync.

Source

Thrown at cmd/bd/linear.go:656

			return "", fmt.Errorf("generating Linear milestone epic ID: %w", err)
		}
	}
	if err := st.CreateIssue(ctx, epic, actor); err != nil {
		return "", fmt.Errorf("creating Linear milestone epic %q: %w", title, err)
	}
	return ref, nil
}

func findLinearMilestoneEpic(ctx context.Context, st storage.Storage, ref, milestoneID, title string) (*types.Issue, error) {
	if existing, err := st.GetIssueByExternalRef(ctx, ref); err == nil {
		return existing, nil
	} else if !errors.Is(err, storage.ErrNotFound) {
		return nil, err
	}

	issues, err := st.SearchIssues(ctx, "", types.IssueFilter{})
	if err != nil {
		return nil, fmt.Errorf("searching local issues for Linear milestone %s: %w", milestoneID, err)
	}
	for _, issue := range issues {
		if issueHasLinearMilestoneID(issue, milestoneID) {
			return issue, nil
		}
	}

	for _, issue := range issues {
		if issue.IssueType != types.TypeEpic || !strings.EqualFold(strings.TrimSpace(issue.Title), title) {
			continue
		}
		ref := ""
		if issue.ExternalRef != nil {
			ref = strings.TrimSpace(*issue.ExternalRef)
		}
		if ref == "" {
			return issue, nil
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped storage error and restore DB connectivity
  2. Re-run the sync; the lookup is read-only and safe to retry
  3. If searches repeatedly fail on large workspaces, ensure the epic's external ref is set so the fast GetIssueByExternalRef path succeeds and the scan fallback is never needed
Defensive patterns

Strategy: try-catch

Validate before calling

// check storage health before the scan-heavy fallback
if err := st.Ping(ctx); err != nil {
    return nil, fmt.Errorf("storage unavailable before milestone lookup: %w", err)
}

Type guard

func isNotFoundErr(err error) bool { return errors.Is(err, storage.ErrNotFound) }

Try / catch

issues, err := st.SearchIssues(ctx, "", types.IssueFilter{})
if err != nil {
    if isTransient(err) { /* backoff and retry once */ }
    return nil, fmt.Errorf("searching local issues for Linear milestone %s: %w", milestoneID, err)
}

Prevention

When it happens

Trigger: Linear milestone sync where GetIssueByExternalRef returns not-found (and not storage.ErrNotFound edge cases) and the fallback st.SearchIssues(ctx, "", IssueFilter{}) errors — storage outage, large-workspace query failure, corrupted index.

Common situations: Database unavailable during import; very large workspaces where the unfiltered search times out; storage backend misconfiguration in the workspace.

Related errors


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