gastownhall/beads · error

building label cache for team %s: %w

Error message

building label cache for team %s: %w

What it means

Returned by Tracker.BatchPush when BuildLabelCache fails for one of the configured teams. Per-team label caches are built up front so each update/create maps beads labels to the right team's Linear label IDs; any team's failure aborts the batch.

Source

Thrown at internal/linear/tracker.go:323

		}
		teamCaches[teamID] = cache
	}

	// The primary team's cache is used for creates, which always target the primary team.
	primaryCache := teamCaches[t.teamIDs[0]]
	if primaryCache == nil {
		return nil, fmt.Errorf("building state cache: no cache for primary team %s", t.teamIDs[0])
	}

	teamLabelCaches := make(map[string]*LabelCache, len(t.teamIDs))
	for _, teamID := range t.teamIDs {
		teamClient := t.clients[teamID]
		if teamClient == nil {
			continue
		}
		lc, err := BuildLabelCache(ctx, teamClient)
		if err != nil {
			return nil, fmt.Errorf("building label cache for team %s: %w", teamID, err)
		}
		teamLabelCaches[teamID] = lc
	}
	primaryLabelCache := teamLabelCaches[t.teamIDs[0]]
	if primaryLabelCache == nil {
		return nil, fmt.Errorf("building label cache: no cache for primary team %s", t.teamIDs[0])
	}

	result := &tracker.BatchPushResult{}

	var toCreate []*types.Issue
	var toUpdate []*types.Issue

	for _, issue := range issues {
		extRef := ""
		if issue.ExternalRef != nil {
			extRef = *issue.ExternalRef
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Confirm all configured teams exist in Linear and the API key can read their labels
  2. Retry after rate-limit backoff; batch pushes hitting several teams are prone to limits
  3. Prune stale team entries from the beads linear config
  4. Check the wrapped error for the HTTP/GraphQL cause before changing config
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: read labels for each configured team before pushing
for _, teamID := range cfg.Linear.TeamIDs {
    if _, err := fetchLabelsForTeam(ctx, apiKey, teamID); err != nil {
        return fmt.Errorf("labels unreachable for team %s: %w", teamID, err)
    }
}

Try / catch

result, err := tracker.BatchPush(ctx, issues, forceIDs)
if err != nil && strings.Contains(err.Error(), "building label cache for team") {
    if isRateLimited(err) {
        time.Sleep(rateLimitBackoff(err))
        result, err = tracker.BatchPush(ctx, issues, forceIDs)
    }
}

Prevention

When it happens

Trigger: BatchPush called when the labels query for team %s fails: token lacking read access to that team's labels, network error, rate limit, or the team ID is stale/deleted in Linear.

Common situations: Same multi-team drift as the state-cache failure: teams removed in Linear but still configured; API key scope/permission gaps per team; rate limiting when many teams are synced in one batch.

Related errors


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