{"record":{"id":"67b311cff00c871a","repo":"gastownhall/beads","slug":"fetching-workflow-states-for-team-s-w","errorCode":null,"errorMessage":"fetching workflow states for team %s: %w","messagePattern":"fetching workflow states for team (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/tracker.go","lineNumber":627,"sourceCode":"\t\treturn fmt.Errorf(\"%s\", missingExplicitStateMapMessage)\n\t}\n\tstatuses := []types.Status{\n\t\ttypes.StatusOpen,\n\t\ttypes.StatusInProgress,\n\t\ttypes.StatusBlocked,\n\t\ttypes.StatusClosed,\n\t\ttypes.StatusDeferred,\n\t\ttypes.StatusPinned,\n\t\ttypes.StatusHooked,\n\t}\n\tfor _, teamID := range t.teamIDs {\n\t\tclient := t.clients[teamID]\n\t\tif client == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcache, err := BuildStateCache(ctx, client)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"fetching workflow states for team %s: %w\", teamID, err)\n\t\t}\n\t\tfor _, status := range statuses {\n\t\t\tif _, err := ResolveStateIDForBeadsStatus(cache, status, t.config); err != nil {\n\t\t\t\tif skipOptionalPushStateMapping(status, err, t.config.CustomStatuses) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tfor _, cs := range t.config.CustomStatuses {\n\t\t\tst := types.Status(cs.Name)\n\t\t\tif _, err := ResolveStateIDForBeadsStatus(cache, st, t.config); err != nil {\n\t\t\t\tif skipOptionalPushStateMapping(st, err, t.config.CustomStatuses) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t}","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/tracker.go#L609-L645","documentation":"While validating push mappings, the tracker fetches Linear's workflow states for each configured team to resolve state IDs. This error wraps any failure from BuildStateCache (network errors, auth failures, API errors) with the team ID for context. It means the validation could not even see what states exist for that team.","triggerScenarios":"BuildStateCache(ctx, client) returns an error during ValidatePushStateMappings for a given teamID — typically when the Linear GraphQL API is unreachable, the API key is invalid/expired, or the team ID no longer exists.","commonSituations":"Expired or rotated Linear API key; offline/VPN-blocked environment; team deleted or renamed in Linear so the configured team ID is stale; Linear API outage or rate limiting.","solutions":["Verify connectivity to Linear's API and retry the sync/push.","Check that the Linear API key in the config is valid and has not expired; re-run 'bd linear link' if needed.","Confirm each configured team ID still exists in Linear and remove/update stale teams.","Read the wrapped inner error (%w) for the precise API/network cause."],"exampleFix":"// before\nerr := tracker.ValidatePushStateMappings(ctx) // wraps: fetching workflow states for team X\n// after\nif err := tracker.ValidatePushStateMappings(ctx); err != nil {\n    log.Printf(\"linear validation failed: %v\", err) // inspect wrapped cause\n}\n// ensure API key valid, then retry","handlingStrategy":"retry","validationCode":"if err := client.Ping(ctx); err != nil {\n    return fmt.Errorf(\"linear API unreachable before sync: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := tracker.ValidatePushStateMappings(ctx); err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded) {\n        return retryWithBackoff(ctx, op)\n    }\n    return err\n}","preventionTips":["Rotate and test the Linear API key regularly.","Check team IDs after renaming/deleting teams in Linear.","Add retry-with-backoff around Linear API operations."],"tags":["linear","network","api","workflow-states"],"backgroundTag":"api-fetch-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}