gastownhall/beads · error
failed to get issue links: %w
Error message
failed to get issue links: %w
What it means
GetIssueLinks failed at the HTTP layer when fetching links (related issues) for an issue IID. The doRequest error is wrapped verbatim.
Source
Thrown at internal/gitlab/client.go:385
respBody, _, err := c.doRequest(ctx, http.MethodPut, urlStr, updates)
if err != nil {
return nil, fmt.Errorf("failed to update issue: %w", err)
}
var issue Issue
if err := json.Unmarshal(respBody, &issue); err != nil {
return nil, fmt.Errorf("failed to parse update response: %w", err)
}
return &issue, nil
}
// GetIssueLinks retrieves issue links for the specified issue IID.
func (c *Client) GetIssueLinks(ctx context.Context, iid int) ([]IssueLink, error) {
urlStr := c.buildURL("/projects/"+c.projectPath()+"/issues/"+strconv.Itoa(iid)+"/links", nil)
respBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)
if err != nil {
return nil, fmt.Errorf("failed to get issue links: %w", err)
}
var links []IssueLink
if err := json.Unmarshal(respBody, &links); err != nil {
return nil, fmt.Errorf("failed to parse issue links response: %w", err)
}
return links, nil
}
// FetchIssueByIID retrieves a single issue by its project-scoped IID.
func (c *Client) FetchIssueByIID(ctx context.Context, iid int) (*Issue, error) {
urlStr := c.buildURL("/projects/"+c.projectPath()+"/issues/"+strconv.Itoa(iid), nil)
respBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)
if err != nil {
return nil, fmt.Errorf("failed to fetch issue %d: %w", iid, err)
}
View on GitHub (pinned to 71377f2769)
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
Example fix
// before
links, err := client.GetIssueLinks(ctx, iid)
// after
if _, err := client.FetchIssueByIID(ctx, iid); err != nil {
return fmt.Errorf("issue %d not found in project: %w", iid, err)
}
links, err := client.GetIssueLinks(ctx, iid) Defensive patterns
Strategy: validation
Validate before calling
if iid <= 0 { return errors.New("invalid iid") }
resp, _ := http.Get(baseURL + "/api/v4/projects/" + proj + "/issues/" + strconv.Itoa(iid))
if resp.StatusCode == 404 { return fmt.Errorf("issue %d does not exist", iid) } Type guard
func isLinksFetchErr(err error) bool {
return strings.Contains(err.Error(), "failed to get issue links")
} Try / catch
links, err := client.GetIssueLinks(ctx, iid)
if err != nil {
if strings.Contains(err.Error(), "404") {
return nil // treat as no links rather than fatal
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- failed to create issue: %w
- failed to update issue: %w
- request failed (attempt %d/%d): %w
- failed to read response (attempt %d/%d): %w
- API error: %s (status %d)
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8afa8fa7e1e16641.
Report an issue: GitHub.