github/github-mcp-server · error
failed to read response body: %w
Error message
failed to read response body: %w
What it means
get_secret_scanning_alert received a non-200 from the secret scanning API, and reading that error body with io.ReadAll failed. The original status (404 unknown alert number, 403 missing security_events scope or secret scanning disabled, 429) is masked by this secondary network failure. The error body is tiny, so a read failure means the connection broke or was cancelled right after headers.
Source
Thrown at pkg/github/secret_scanning.go:83
client, err := deps.GetClient(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err)
}
alert, resp, err := client.SecretScanning.GetAlert(ctx, owner, repo, int64(alertNumber))
if err != nil {
return ghErrors.NewGitHubAPIErrorResponse(ctx,
fmt.Sprintf("failed to get alert with number '%d'", alertNumber),
resp,
err,
), nil, nil
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, nil, fmt.Errorf("failed to read response body: %w", err)
}
return ghErrors.NewGitHubAPIStatusErrorResponse(ctx, "failed to get alert", resp, body), nil, nil
}
r, err := json.Marshal(alert)
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal alert: %w", err)
}
result := utils.NewToolResultText(string(r))
// Secret scanning alerts are access-restricted regardless of repo
// visibility and surface the matched secret material itself, so the
// label is always private-untrusted.
result = attachStaticIFCLabel(ctx, deps, result, ifc.LabelSecurityAlert())
return result, nil, nil
},
)
}View on GitHub (pinned to 0ea1f775a7)
Solutions
- Retry the tool call once - both the masked status and the body-read failure are usually transient
- If repeatable, increase the per-request context deadline so it outlives the full response
- Patch the handler to fall back to resp.StatusCode when the body is unreadable, so 404/403 are still distinguishable
Example fix
// after
return nil, nil, fmt.Errorf("failed to get alert: status %d (body unreadable: %w)", resp.StatusCode, err) Defensive patterns
Strategy: retry
Type guard
func isBodyReadFailure(err error) bool {
var netErr net.Error
return errors.As(err, &netErr) || errors.Is(err, io.ErrUnexpectedEOF)
} Try / catch
result, extra, err := callTool(ctx, "get_secret_scanning_alert", args)
if err != nil && strings.Contains(err.Error(), "failed to read response body") {
// the real HTTP status was masked; retry once
result, extra, err = callTool(ctx, "get_secret_scanning_alert", args)
}
if err != nil {
return fmt.Errorf("get_secret_scanning_alert failed (status masked): %w", err)
} Prevention
- Set per-request deadlines that outlive full response bodies, not just headers
- Retry once on body-read failures before reporting - the masked status is often transient
- Patch the handler to emit resp.StatusCode alongside the read error
When it happens
Trigger: SecretScanning.GetAlert returns non-2xx and the stream resets before the body completes; client context cancelled mid-response; proxies tearing down error responses immediately.
Common situations: Context deadlines almost equal to the API latency; flaky egress networks in CI; rare in steady-state operation.
Related errors
- failed to read response body: %w
- failed to read response body: %w
- failed to read response body: %w
- failed to read file content: %w
- GitHub App authentication requires a private key: set GITHUB
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/732ada5dcfda6cd3.
Report an issue: GitHub.