{"record":{"id":"0b24bf8db15d9f8e","repo":"github/github-mcp-server","slug":"failed-to-read-response-body-w-0b24bf","errorCode":null,"errorMessage":"failed to read response body: %w","messagePattern":"failed to read response body: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/github/projects.go","lineNumber":1348,"sourceCode":"\t}\n\treturn !project.GetPublic(), nil\n}\n\nfunc getProject(ctx context.Context, client *github.Client, owner, ownerType string, projectNumber int) (*mcp.CallToolResult, bool, any, error) {\n\tproject, resp, err := fetchProjectV2(ctx, client, owner, ownerType, projectNumber)\n\tif err != nil {\n\t\treturn ghErrors.NewGitHubAPIErrorResponse(ctx,\n\t\t\t\"failed to get project\",\n\t\t\tresp,\n\t\t\terr,\n\t\t), false, nil, nil\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tbody, err := io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn nil, false, nil, fmt.Errorf(\"failed to read response body: %w\", err)\n\t\t}\n\t\treturn ghErrors.NewGitHubAPIStatusErrorResponse(ctx, \"failed to get project\", resp, body), false, nil, nil\n\t}\n\n\tminimalProject := convertToMinimalProject(project)\n\tr, err := json.Marshal(minimalProject)\n\tif err != nil {\n\t\treturn nil, false, nil, fmt.Errorf(\"failed to marshal response: %w\", err)\n\t}\n\n\treturn utils.NewToolResultText(string(r)), !project.GetPublic(), nil, nil\n}\n\nfunc getProjectField(ctx context.Context, client *github.Client, owner, ownerType string, projectNumber int, fieldID int64) (*mcp.CallToolResult, any, error) {\n\tvar resp *github.Response\n\tvar projectField *github.ProjectV2Field\n\tvar err error\n","sourceCodeStart":1330,"sourceCodeEnd":1366,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/github/projects.go#L1330-L1366","documentation":"Returned by getProject when the GitHub REST API answers a non-200 status (e.g. 404, 403) and reading the response body for the error payload itself fails with io.ReadAll. The double failure (API error + unreadable body) prevents building the structured GitHubAPIStatusErrorResponse. Typically indicates the connection was torn down mid-response, a proxy truncated the body, or the body was already consumed.","triggerScenarios":"GitHub or an intermediate proxy closes the connection before the error body is fully transmitted (race with rate-limit resets or LB idle timeouts); TLS interruption mid-body; a transport retry that already drained resp.Body; extremely large error payloads hitting reader limits.","commonSituations":"Flaky corporate networks and TLS-terminating proxies; GHES instances behind aggressive load balancers; running under constrained CI egress where responses are truncated; retry wrappers that consume bodies.","solutions":["Retry the tool call once — transient transport truncation usually clears","Check network stability between the server and api.github.com (or GHES host): proxies, MTU, idle timeouts","If a custom http.Client/Transport wraps requests, ensure it does not consume and close resp.Body before the handler reads it","Capture transport-level logs (GITHUB_TOKEN ok? proxy env set?) when it recurs, and report with the status code you saw"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// nothing to validate client-side; you can pre-check connectivity/egress health before long crawls\nfunc egressHealthy(ctx context.Context, host string) error {\n    c := http.Client{Timeout: 5 * time.Second}\n    r, err := c.Head(\"https://\" + host)\n    if err != nil {\n        return err\n    }\n    _ = r.Body.Close()\n    return nil\n}","typeGuard":null,"tryCatchPattern":"res, isPrivate, r, err := getProject(ctx, client, owner, ownerType, number)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to read response body\") {\n        // transient transport truncation: safe to retry once with backoff\n        time.Sleep(500 * time.Millisecond)\n        res, isPrivate, r, err = getProject(ctx, client, owner, ownerType, number)\n    }\n    if err != nil {\n        return err\n    }\n}","preventionTips":["Wrap tool calls with one bounded retry on transport-level failures","Ensure proxies/load balancers between the server and GitHub allow full error bodies (no early connection close)","If you use custom Transports/retries, never drain resp.Body before the handler reads it","Log response status alongside the read failure to distinguish GitHub-side from network-side causes"],"tags":["go","network","github-api","response-body","transient"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}