{"record":{"id":"e5e2e8fdb6d896f9","repo":"gastownhall/beads","slug":"failed-to-fetch-milestones-w","errorCode":null,"errorMessage":"failed to fetch milestones: %w","messagePattern":"failed to fetch milestones: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/gitlab/client.go","lineNumber":425,"sourceCode":"\t}\n\n\treturn &issue, nil\n}\n\n// FetchMilestones retrieves milestones from the project with optional state filter.\n// state can be: \"active\", \"closed\", or \"\" (all).\nfunc (c *Client) FetchMilestones(ctx context.Context, state string) ([]Milestone, error) {\n\tparams := map[string]string{\n\t\t\"per_page\": strconv.Itoa(MaxPageSize),\n\t}\n\tif state != \"\" {\n\t\tparams[\"state\"] = state\n\t}\n\n\turlStr := c.buildURL(\"/projects/\"+c.projectPath()+\"/milestones\", params)\n\trespBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch milestones: %w\", err)\n\t}\n\n\tvar milestones []Milestone\n\tif err := json.Unmarshal(respBody, &milestones); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse milestones response: %w\", err)\n\t}\n\n\treturn milestones, nil\n}\n\n// FetchMilestoneByIID retrieves a single milestone by its project-scoped IID.\n// Returns nil if no milestone matches the given IID.\nfunc (c *Client) FetchMilestoneByIID(ctx context.Context, iid int) (*Milestone, error) {\n\tparams := map[string]string{\n\t\t\"iids[]\": strconv.Itoa(iid),\n\t}\n\n\turlStr := c.buildURL(\"/projects/\"+c.projectPath()+\"/milestones\", params)","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/gitlab/client.go#L407-L443","documentation":"FetchMilestones GETs /projects/:id/milestones through doRequest, which manages authentication, retries, and HTTP status handling. This error wraps any doRequest failure — network errors, timeouts, context cancellation, or HTTP error statuses from GitLab. It is raised before JSON parsing, so the request never produced a usable response.","triggerScenarios":"Calling Client.FetchMilestones with an invalid state value (GitLab rejects it with 400), bad/expired credentials (401/403), wrong project path, network outage, or a cancelled context.","commonSituations":"Passing a state other than active/closed (e.g. \"open\", which is GitHub-style); PAT expired or missing read_api scope; misconfigured project namespace; CI environments without network egress to GitLab.","solutions":["Unwrap the error to inspect the HTTP status; a 400 usually means an invalid state parameter","Only pass \"active\", \"closed\", or \"\" (all) as the state argument","Check token validity/scopes and the configured project path","For transport errors, verify connectivity to the GitLab host and retry with backoff"],"exampleFix":"// before\nms, err := client.FetchMilestones(ctx, \"open\") // invalid state\n// after\nstate := \"open\"\nif state != \"active\" && state != \"closed\" { state = \"\" }\nms, err := client.FetchMilestones(ctx, state)","handlingStrategy":"validation","validationCode":"func validMilestoneState(s string) bool {\n    return s == \"\" || s == \"active\" || s == \"closed\"\n}\n// before calling:\nif !validMilestoneState(state) {\n    return fmt.Errorf(\"invalid milestone state %q (use active, closed, or empty)\", state)\n}","typeGuard":null,"tryCatchPattern":"ms, err := client.FetchMilestones(ctx, state)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return fetchMilestonesWithRetry(ctx, state)\n    }\n    return fmt.Errorf(\"list milestones: %w\", err)\n}","preventionTips":["Only pass \"active\", \"closed\", or \"\" — not GitHub-style values like \"open\"","Validate the project path configuration before bulk queries","Keep PATs valid and scoped with read_api","Retry transient transport errors with backoff rather than failing the whole run"],"tags":["gitlab","network","http","milestones"],"backgroundTag":"http-request-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}