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
- Confirm all configured teams exist in Linear and the API key can read their labels
- Retry after rate-limit backoff; batch pushes hitting several teams are prone to limits
- Prune stale team entries from the beads linear config
- 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
- Space out multi-team batches to avoid label-query rate limits
- Keep tokens scoped to read labels on all synced teams
- Remove teams from config once deleted from Linear
- Honor Linear's rate-limit headers in retry logic
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
- loading team labels: %w
- building state cache for team %s: %w
- fetching issues from team %s: %w
- finding state for status %s: %w
- cannot determine Linear team for issue %s
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/e3210bd64d0f3927.
Report an issue: GitHub.