{"record":{"id":"3196c6efc43c1ad5","repo":"gastownhall/beads","slug":"building-state-cache-no-cache-for-primary-team-s","errorCode":null,"errorMessage":"building state cache: no cache for primary team %s","messagePattern":"building state cache: no cache for primary team (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/tracker.go","lineNumber":312,"sourceCode":"\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 {\n\t\t\treturn nil, fmt.Errorf(\"building label cache for team %s: %w\", teamID, err)\n\t\t}\n\t\tteamLabelCaches[teamID] = lc\n\t}\n\tprimaryLabelCache := teamLabelCaches[t.teamIDs[0]]\n\tif primaryLabelCache == nil {\n\t\treturn nil, fmt.Errorf(\"building label cache: no cache for primary team %s\", t.teamIDs[0])\n\t}","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/tracker.go#L294-L330","documentation":"Returned by Tracker.BatchPush when no state cache exists for the primary team after the per-team build loop. This happens when the primary team's entry was skipped in the loop (nil team client) or absent from t.clients, so creates—which always target the primary team—cannot proceed.","triggerScenarios":"BatchPush called where t.teamIDs[0] has a nil entry in t.clients (team configured by ID but its client construction failed or was skipped), leaving teamCaches[teamIDs[0]] unset.","commonSituations":"Partially initialized trackers in tests; config listing a primary team whose client failed to build (bad credentials scoped to another team); race or ordering issue where teamIDs was set after clients map was built.","solutions":["Ensure the primary team's Linear client is constructed successfully before BatchPush","Check that teamIDs and the clients map are populated consistently (SetTeamIDs called before use)","Verify credentials grant access to the primary team specifically","Re-initialize the tracker; if in tests, register a fake client for the primary team"],"exampleFix":"// before\nt.SetTeamIDs([]string{\"ENG\"}) // but t.clients[\"ENG\"] never built\n// after\nt.Init(ctx, cfg) // builds clients for all teamIDs, including primary\nif t.clients[\"ENG\"] == nil { t.SkipLinear = true }","handlingStrategy":"validation","validationCode":"// Pre-check: primary team must have a live client before batch operations\nprimary := tracker.PrimaryTeamID()\nif tracker.ClientForTeam(primary) == nil {\n    return fmt.Errorf(\"primary Linear team %s has no client; run Init first\", primary)\n}","typeGuard":null,"tryCatchPattern":"result, err := tracker.BatchPush(ctx, issues, forceIDs)\nif err != nil && strings.Contains(err.Error(), \"no cache for primary team\") {\n    // re-initialize the tracker then retry once\n    if rerr := tracker.Init(ctx, cfg); rerr == nil {\n        result, err = tracker.BatchPush(ctx, issues, forceIDs)\n    }\n}","preventionTips":["Always call Init (not just SetTeamIDs) before batch operations","In tests, register a fake client for every team ID including the primary","Assert t.clients covers teamIDs after initialization","Treat client-build failures as fatal instead of silently skipping teams"],"tags":["linear","state-cache","initialization","batch"],"backgroundTag":"linear-team-client-not-initialized","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}