{"record":{"id":"8afa8fa7e1e16641","repo":"gastownhall/beads","slug":"failed-to-get-issue-links-w","errorCode":null,"errorMessage":"failed to get issue links: %w","messagePattern":"failed to get issue links: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/gitlab/client.go","lineNumber":385,"sourceCode":"\trespBody, _, err := c.doRequest(ctx, http.MethodPut, urlStr, updates)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to update issue: %w\", err)\n\t}\n\n\tvar issue Issue\n\tif err := json.Unmarshal(respBody, &issue); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse update response: %w\", err)\n\t}\n\n\treturn &issue, nil\n}\n\n// GetIssueLinks retrieves issue links for the specified issue IID.\nfunc (c *Client) GetIssueLinks(ctx context.Context, iid int) ([]IssueLink, error) {\n\turlStr := c.buildURL(\"/projects/\"+c.projectPath()+\"/issues/\"+strconv.Itoa(iid)+\"/links\", nil)\n\trespBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get issue links: %w\", err)\n\t}\n\n\tvar links []IssueLink\n\tif err := json.Unmarshal(respBody, &links); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse issue links response: %w\", err)\n\t}\n\n\treturn links, nil\n}\n\n// FetchIssueByIID retrieves a single issue by its project-scoped IID.\nfunc (c *Client) FetchIssueByIID(ctx context.Context, iid int) (*Issue, error) {\n\turlStr := c.buildURL(\"/projects/\"+c.projectPath()+\"/issues/\"+strconv.Itoa(iid), nil)\n\trespBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch issue %d: %w\", iid, err)\n\t}\n","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/gitlab/client.go#L367-L403","documentation":"GetIssueLinks failed at the HTTP layer when fetching links (related issues) for an issue IID. The doRequest error is wrapped verbatim.","triggerScenarios":"GET /projects/:id/issues/:iid/links fails: 404 (wrong iid/project path), 401/403 (token lacks read_api or the issue is confidential), 5xx, rate limit, or network/context error.","commonSituations":"Issue links feature unavailable on older GitLab versions, confidential issues queried with a low-privilege token, wrong project path configured, or IID typo from another project.","solutions":["Check the wrapped status: 404 → verify iid and projectPath; 401/403 → use a token with read_api and access to the issue","Confirm the GitLab version supports the issue links API (>= 10.3 for basic links)","Fetch the issue first (FetchIssueByIID) to validate iid before listing links","Retry with backoff on 429/5xx"],"exampleFix":"// before\nlinks, err := client.GetIssueLinks(ctx, iid)\n// after\nif _, err := client.FetchIssueByIID(ctx, iid); err != nil {\n\treturn fmt.Errorf(\"issue %d not found in project: %w\", iid, err)\n}\nlinks, err := client.GetIssueLinks(ctx, iid)","handlingStrategy":"validation","validationCode":"if iid <= 0 { return errors.New(\"invalid iid\") }\nresp, _ := http.Get(baseURL + \"/api/v4/projects/\" + proj + \"/issues/\" + strconv.Itoa(iid))\nif resp.StatusCode == 404 { return fmt.Errorf(\"issue %d does not exist\", iid) }","typeGuard":"func isLinksFetchErr(err error) bool {\n\treturn strings.Contains(err.Error(), \"failed to get issue links\")\n}","tryCatchPattern":"links, err := client.GetIssueLinks(ctx, iid)\nif err != nil {\n\tif strings.Contains(err.Error(), \"404\") {\n\t\treturn nil // treat as no links rather than fatal\n\t}\n\treturn err\n}","preventionTips":["Ensure the token can read confidential issues when needed (higher access level)","Confirm GitLab server version supports the issue links API","Verify iids belong to the configured project","Handle 404/403 gracefully as \"no links visible\" in aggregations"],"tags":["gitlab","network","auth"],"backgroundTag":"http-request-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}