{"record":{"id":"90f817853d0a9014","repo":"github/github-mcp-server","slug":"failed-to-list-global-security-advisories-w","errorCode":null,"errorMessage":"failed to list global security advisories: %w","messagePattern":"failed to list global security advisories: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/github/security_advisories.go","lineNumber":190,"sourceCode":"\t\t\t\topts.IsWithdrawn = &isWithdrawn\n\t\t\t}\n\n\t\t\tif affects != \"\" {\n\t\t\t\topts.Affects = &affects\n\t\t\t}\n\t\t\tif published != \"\" {\n\t\t\t\topts.Published = &published\n\t\t\t}\n\t\t\tif updated != \"\" {\n\t\t\t\topts.Updated = &updated\n\t\t\t}\n\t\t\tif modified != \"\" {\n\t\t\t\topts.Modified = &modified\n\t\t\t}\n\n\t\t\tadvisories, resp, err := client.SecurityAdvisories.ListGlobalSecurityAdvisories(ctx, opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"failed to list global security advisories: %w\", err)\n\t\t\t}\n\t\t\tdefer func() { _ = resp.Body.Close() }()\n\n\t\t\tif resp.StatusCode != http.StatusOK {\n\t\t\t\tbody, err := io.ReadAll(resp.Body)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, nil, fmt.Errorf(\"failed to read response body: %w\", err)\n\t\t\t\t}\n\t\t\t\treturn ghErrors.NewGitHubAPIStatusErrorResponse(ctx, \"failed to list advisories\", resp, body), nil, nil\n\t\t\t}\n\n\t\t\tr, err := json.Marshal(advisories)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"failed to marshal advisories: %w\", err)\n\t\t\t}\n\n\t\t\tresult := utils.NewToolResultText(string(r))\n\t\t\t// Global advisories come from the world-readable GitHub Advisory","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/github/security_advisories.go#L172-L208","documentation":"client.SecurityAdvisories.ListGlobalSecurityAdvisories returned a non-nil error. Unlike sibling handlers, this one returns the raw wrapped error instead of ghErrors.NewGitHubAPIErrorResponse, so both transport failures and GitHub API errors surface here together; go-github's *github.ErrorResponse inside carries the status and message. Common causes: 422 invalid filter values, 403 rate limit exhausted, and DNS/TLS failures to the API host.","triggerScenarios":"Invalid `ecosystem` or `affects` filter strings (422 Unprocessable Entity); primary rate limit exhausted (403 with x-ratelimit-remaining: 0); malformed date ranges in published/updated/modified; network-level failures reaching api.github.com.","commonSituations":"Passing an ecosystem not in the allowed enum; tight pagination loops ignoring rate-limit headers; egress proxies blocking or intercepting api.github.com TLS.","solutions":["Unwrap with errors.As(err, *github.ErrorResponse) and read Message/Status: 422 means fix the offending filter argument","On 403/429, wait until x-ratelimit-reset and retry with fewer, larger pages","On transport errors, verify connectivity and TLS to the configured API host","Code improvement: route API errors through NewGitHubAPIErrorResponse for consistent, actionable messages"],"exampleFix":"// before\nadvisories, resp, err := client.SecurityAdvisories.ListGlobalSecurityAdvisories(ctx, opts)\nif err != nil {\n    return nil, nil, fmt.Errorf(\"failed to list global security advisories: %w\", err)\n}\n// after - keep API errors structured, wrap only transport errors\nvar ghErr *github.ErrorResponse\nif errors.As(err, &ghErr) {\n    return ghErrors.NewGitHubAPIErrorResponse(ctx, \"failed to list global security advisories\", resp, err), nil, nil\n}\nreturn nil, nil, fmt.Errorf(\"failed to list global security advisories: %w\", err)","handlingStrategy":"retry","validationCode":"// Validate filter enums/dates before calling the tool\nvalidEcosystems := map[string]bool{\"pip\": true, \"npm\": true, \"maven\": true, \"rubygems\": true,\n\t\"nuget\": true, \"composer\": true, \"go\": true, \"rust\": true, \"erlang\": true,\n\t\"actions\": true, \"pub\": true, \"other\": true}\nif eco != \"\" && !validEcosystems[eco] {\n    return fmt.Errorf(\"ecosystem %q is not one of the allowed values\", eco)\n}\nfor _, d := range []string{published, updated, modified} {\n    if d != \"\" && !validDateOrRange(d) {\n        return fmt.Errorf(\"date filter %q must be an ISO 8601 date or range\", d)\n    }\n}","typeGuard":"func isGitHubAPIError(err error) (*github.ErrorResponse, bool) {\n\tvar ghErr *github.ErrorResponse\n\tif errors.As(err, &ghErr) {\n\t\treturn ghErr, true\n\t}\n\treturn nil, false\n}\n\nfunc isRetryableListErr(err error) bool {\n\tghErr, ok := isGitHubAPIError(err)\n\tif !ok {\n\t\tvar netErr net.Error\n\t\treturn errors.As(err, &netErr) // transport: retry\n\t}\n\treturn ghErr.Response != nil &&\n\t\t(ghErr.Response.StatusCode == 429 || ghErr.Response.StatusCode >= 500)\n}","tryCatchPattern":"advisories, resp, err := client.SecurityAdvisories.ListGlobalSecurityAdvisories(ctx, opts)\nif err != nil {\n    if ghErr, ok := isGitHubAPIError(err); ok {\n        if ghErr.Response.StatusCode == 422 {\n            return nil, fmt.Errorf(\"invalid advisory filter: %s\", ghErr.Message) // fix arguments, do not retry\n        }\n        if isRetryableListErr(err) {\n            time.Sleep(backoff) // 429/5xx: retry with jitter\n            return listAgain(ctx, opts)\n        }\n    }\n    return nil, fmt.Errorf(\"failed to list global security advisories: %w\", err)\n}","preventionTips":["Pass only documented enum values for ecosystem/severity/type and ISO 8601 dates for date filters","Check rate-limit headroom (x-ratelimit-remaining) before each page fetch","Classify *github.ErrorResponse before retrying: 4xx means fix arguments, only 429/5xx/transport retry"],"tags":["go","mcp","github-api","rate-limit","security-advisory","validation"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}