{"record":{"id":"ee9a7e4153bc116b","repo":"gastownhall/beads","slug":"building-state-cache-for-team-s-w","errorCode":null,"errorMessage":"building state cache for team %s: %w","messagePattern":"building state cache for team (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/tracker.go","lineNumber":304,"sourceCode":"// Result mapping: batch-create results are matched by title rather than array\n// index, since Linear's API does not guarantee response order matches input order.\nfunc (t *Tracker) BatchPush(ctx context.Context, issues []*types.Issue, forceIDs map[string]bool) (*tracker.BatchPushResult, error) {\n\tclient := t.primaryClient()\n\tif client == nil {\n\t\treturn nil, fmt.Errorf(\"no Linear client available\")\n\t}\n\n\t// Build per-team state caches so that updates to issues belonging to different\n\t// teams resolve workflow state IDs against the correct team's state list.\n\tteamCaches := make(map[string]*StateCache, len(t.teamIDs))\n\tfor _, teamID := range t.teamIDs {\n\t\tteamClient := t.clients[teamID]\n\t\tif teamClient == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcache, err := BuildStateCache(ctx, teamClient)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"building state cache for team %s: %w\", teamID, err)\n\t\t}\n\t\tteamCaches[teamID] = cache\n\t}\n\n\t// The primary team's cache is used for creates, which always target the primary team.\n\tprimaryCache := teamCaches[t.teamIDs[0]]\n\tif primaryCache == nil {\n\t\treturn nil, fmt.Errorf(\"building state cache: no cache for primary team %s\", t.teamIDs[0])\n\t}\n\n\tteamLabelCaches := make(map[string]*LabelCache, len(t.teamIDs))\n\tfor _, teamID := range t.teamIDs {\n\t\tteamClient := t.clients[teamID]\n\t\tif teamClient == nil {\n\t\t\tcontinue\n\t\t}\n\t\tlc, err := BuildLabelCache(ctx, teamClient)\n\t\tif err != nil {","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/tracker.go#L286-L322","documentation":"Returned by Tracker.BatchPush when BuildStateCache fails for one of the configured teams. BatchPush pre-builds per-team workflow state caches so updates resolve state IDs against the correct team; any team's fetch failure aborts the entire batch.","triggerScenarios":"BatchPush called when the Linear workflow-states query fails for team %s: expired API key lacking that team's access, rate limiting, network error, or the team ID no longer exists in the Linear workspace.","commonSituations":"Multi-team setups where a team was deleted/renamed in Linear but remains in beads config; API key issued before the team was added or scoped to other teams; transient API outages during large batch syncs.","solutions":["Verify every team ID in the beads linear config still exists in the Linear workspace","Ensure the API key has access (member/permission) to all configured teams","Retry — transient rate limits or network errors are common with batch operations","Remove or fix stale team entries in config so BatchPush skips missing teams"],"exampleFix":"// before\nteamIDs = [\"ENG\", \"OLDTEAM\"] // OLDTEAM deleted in Linear\n// after\nteamIDs = [\"ENG\"] // only live teams configured","handlingStrategy":"validation","validationCode":"// Verify all configured teams exist and are accessible before pushing\nfor _, teamID := range cfg.Linear.TeamIDs {\n    if err := verifyTeamAccessible(ctx, apiKey, teamID); err != nil {\n        return fmt.Errorf(\"team %s inaccessible: %w\", teamID, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"result, err := tracker.BatchPush(ctx, issues, forceIDs)\nif err != nil {\n    var teamErr TeamCacheError\n    if errors.As(err, &teamErr) || strings.Contains(err.Error(), \"building state cache for team\") {\n        // retry only the affected team's issues\n        return retryTeam(teamErr.TeamID, issues)\n    }\n    return err\n}","preventionTips":["Prune team IDs deleted from Linear out of beads config","Scope the API key to all synced teams (or use per-team keys)","Apply backoff on rate limits before large multi-team batches","Test multi-team configs with a dry-run push"],"tags":["linear","state-cache","multi-team","api"],"backgroundTag":"linear-api-fetch-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}