{"record":{"id":"82cdb01ff1a071cd","repo":"gastownhall/beads","slug":"failed-to-fetch-projects-w","errorCode":null,"errorMessage":"failed to fetch projects: %w","messagePattern":"failed to fetch projects: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/client.go","lineNumber":1475,"sourceCode":"\t}\n\n\tfor {\n\t\tvariables := map[string]interface{}{\n\t\t\t\"filter\": filter,\n\t\t\t\"first\":  MaxPageSize,\n\t\t}\n\t\tif cursor != \"\" {\n\t\t\tvariables[\"after\"] = cursor\n\t\t}\n\n\t\treq := &GraphQLRequest{\n\t\t\tQuery:     projectsQuery,\n\t\t\tVariables: variables,\n\t\t}\n\n\t\tdata, err := c.Execute(ctx, req)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to fetch projects: %w\", err)\n\t\t}\n\n\t\tvar projectsResp ProjectsResponse\n\t\tif err := json.Unmarshal(data, &projectsResp); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse projects response: %w\", err)\n\t\t}\n\n\t\tallProjects = append(allProjects, projectsResp.Projects.Nodes...)\n\n\t\tif !projectsResp.Projects.PageInfo.HasNextPage {\n\t\t\tbreak\n\t\t}\n\t\tcursor = projectsResp.Projects.PageInfo.EndCursor\n\t}\n\n\treturn allProjects, nil\n}\n","sourceCodeStart":1457,"sourceCodeEnd":1493,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/client.go#L1457-L1493","documentation":"FetchProjects pages through Linear projects (projectsQuery with team filter, optional state, first: MaxPageSize, cursor pagination). This error wraps any Execute failure on a page fetch: network error, HTTP error, GraphQL error, or context cancellation. Because it runs in a pagination loop, a failure on any page aborts the whole listing.","triggerScenarios":"c.Execute fails mid-pagination: token lacks project read scope, team filter references a team ID the token can't see, invalid `state` filter value, rate limit on a large workspace, network blip between pages, or ctx deadline exceeded during a long crawl.","commonSituations":"Listing projects on a big workspace hits 429s mid-loop; c.TeamID configured from another workspace; using a state string outside planned/started/paused/completed/canceled; long-running sync whose context times out on page 3+.","solutions":["Unwrap the error to find the underlying cause (transport vs GraphQL vs context).","Validate c.TeamID against FetchTeams — a wrong team ID causes GraphQL errors on every page.","Check the state argument is one of planned/started/paused/completed/canceled (or \"all\"/\"\").","Implement retry-with-backoff per page and reuse the last good cursor so you don't restart from page 1.","Watch for 429s in the wrapped error and slow the request rate (Linear rate limits)."],"exampleFix":"// before\nprojects, err := client.FetchProjects(ctx, \"active\") // invalid state value\n// after\nprojects, err := client.FetchProjects(ctx, \"started\") // planned|started|paused|completed|canceled|all|\"\"","handlingStrategy":"retry","validationCode":"// validate state argument and team id before the paginated call\nvalidStates := map[string]bool{\"planned\":true,\"started\":true,\"paused\":true,\"completed\":true,\"canceled\":true,\"all\":true,\"\":true}\nif !validStates[state] {\n    return fmt.Errorf(\"invalid project state %q\", state)\n}\nif client.TeamID == \"\" {\n    return fmt.Errorf(\"TeamID not configured\")\n}","typeGuard":null,"tryCatchPattern":"projects, err := client.FetchProjects(ctx, \"started\")\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)\n        defer cancel()\n        return client.FetchProjects(ctx, \"started\") // read-only: safe to retry\n    }\n    return fmt.Errorf(\"list projects: %w\", err)\n}","preventionTips":["Use a per-call context timeout generous enough for multi-page crawls of large workspaces.","Validate TeamID with FetchTeams during configuration.","Restrict state to the documented enum values.","Add backoff on 429s; pagination loops amplify rate limiting.","Treat the call as idempotent (read-only) — safe to retry from scratch."],"tags":["go","graphql","pagination","network","linear-api"],"backgroundTag":"graphql-request-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}