{"record":{"id":"96236dcaab5b1ed8","repo":"gastownhall/beads","slug":"failed-to-fetch-milestone-by-iid-d-w","errorCode":null,"errorMessage":"failed to fetch milestone by IID %d: %w","messagePattern":"failed to fetch milestone by IID (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/gitlab/client.go","lineNumber":446,"sourceCode":"\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)\n\trespBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch milestone by IID %d: %w\", iid, 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 milestone response: %w\", err)\n\t}\n\n\tif len(milestones) == 0 {\n\t\treturn nil, nil\n\t}\n\n\treturn &milestones[0], nil\n}\n\n// CreateMilestone creates a new milestone in GitLab.\nfunc (c *Client) CreateMilestone(ctx context.Context, title, description string) (*Milestone, error) {\n\tbody := map[string]interface{}{\n\t\t\"title\":       title,","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/gitlab/client.go#L428-L464","documentation":"FetchMilestoneByIID queries /projects/:id/milestones with an iids[] filter via doRequest, which handles auth, retries, and HTTP errors. This error wraps any doRequest failure — network errors, timeouts, context cancellation, or HTTP error statuses (401/403/500) returned by GitLab. It is raised before JSON parsing, so the request never completed successfully.","triggerScenarios":"Calling Client.FetchMilestoneByIID with expired/invalid credentials, a misconfigured project path, network outage, or a cancelled context while the filtered milestones query runs.","commonSituations":"PAT expired or lacking read_api scope; project namespace changed/renamed so the URL 404s; VPN or proxy blocking the GitLab host in CI; context deadline exceeded on slow GitLab instances.","solutions":["Unwrap the error to read the HTTP status or transport cause (url.Error, context.DeadlineExceeded)","Check token validity and read_api scope; re-authenticate if 401/403","Verify the client's configured project path matches the milestone's project","For timeouts, increase the client timeout or retry; confirm network egress to the GitLab host"],"exampleFix":"// before\nm, err := client.FetchMilestoneByIID(ctx, iid)\nif err != nil { return err }\n// after\nm, err := client.FetchMilestoneByIID(ctx, iid)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return retryWithBackoff(...)\n    }\n    return fmt.Errorf(\"milestone %d lookup: %w\", iid, err)\n}","handlingStrategy":"retry","validationCode":"if iid <= 0 {\n    return fmt.Errorf(\"invalid milestone IID %d\", iid)\n}\nif err := ctx.Err(); err != nil {\n    return err\n}","typeGuard":"func isAuthError(err error) bool {\n    return strings.Contains(err.Error(), \"401\") || strings.Contains(err.Error(), \"403\")\n}","tryCatchPattern":"m, err := client.FetchMilestoneByIID(ctx, iid)\nif err != nil {\n    if isAuthError(err) {\n        return fmt.Errorf(\"check GITLAB token/scopes: %w\", err) // don't retry auth\n    }\n    if isTransient(err) {\n        return fetchMilestoneWithRetry(ctx, iid)\n    }\n    return err\n}","preventionTips":["Validate IIDs are positive integers before querying","Refresh tokens before expiry and grant read_api scope","Set client timeouts generously for slower self-hosted GitLab instances","Confirm CI runners have network egress to the GitLab host"],"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"}