{"record":{"id":"bb3e36deb99677a3","repo":"github/github-mcp-server","slug":"failed-to-read-response-body-w-bb3e36","errorCode":null,"errorMessage":"failed to read response body: %w","messagePattern":"failed to read response body: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/github/repository_resource.go","lineNumber":252,"sourceCode":"\t\t\t\tif err := base64Encoder.Close(); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to close base64 encoder: %w\", err)\n\t\t\t\t}\n\n\t\t\t\treturn &mcp.ReadResourceResult{\n\t\t\t\t\tContents: []*mcp.ResourceContents{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tURI:      request.Params.URI,\n\t\t\t\t\t\t\tMIMEType: mimeType,\n\t\t\t\t\t\t\tBlob:     buf.Bytes(),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}, nil\n\t\t\t}\n\t\tcase resp.StatusCode != http.StatusNotFound:\n\t\t\t// If we got a response but it is not 200 OK, we return an error\n\t\t\tbody, err := io.ReadAll(resp.Body)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to read response body: %w\", err)\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"failed to fetch raw content: %s\", string(body))\n\t\tdefault:\n\t\t\t// This should be unreachable because GetContents should return an error if neither file nor directory content is found.\n\t\t\treturn nil, errors.New(\"404 Not Found\")\n\t\t}\n\t}\n}\n\n// expandRepoResourceURI builds a resource URI using the appropriate URI template\n// based on the provided parameters (sha, ref, or default).\nfunc expandRepoResourceURI(owner, repo, sha, ref string, pathParts []string) (string, error) {\n\tbaseValues := uritemplate.Values{\n\t\t\"owner\": uritemplate.String(owner),\n\t\t\"repo\":  uritemplate.String(repo),\n\t\t\"path\":  uritemplate.List(pathParts...),\n\t}\n","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/github/repository_resource.go#L234-L270","documentation":"In the repo:// resource handler, the raw content request came back with a status other than 200 or 404, and io.ReadAll of that error response body failed. The real API failure (rate limit, auth, 5xx) is masked by this secondary transport error: the message describes the failed body read, not the underlying status, which is lost entirely.","triggerScenarios":"GetRawContent returns 403/429/5xx and the connection breaks or the context deadline expires while streaming even the small error body; client timeouts set so tight the error body cannot be fully read.","commonSituations":"Flaky networks where resets hit right after headers; servers under load where GitHub sends 5xx slowly; hard per-request timeouts in front of the MCP server.","solutions":["Retry the resource read - the masked status was likely transient (429/5xx) and the body-read failure is a network blip","If it repeats, patch the handler to include resp.StatusCode in the error so the real status is never lost","Verify token validity and rate-limit state when the pattern recurs on every call"],"exampleFix":"// before\nbody, err := io.ReadAll(resp.Body)\nif err != nil {\n    return nil, fmt.Errorf(\"failed to read response body: %w\", err)\n}\nreturn nil, fmt.Errorf(\"failed to fetch raw content: %s\", string(body))\n// after - never lose the status code\nreturn nil, fmt.Errorf(\"failed to fetch raw content: status %d (body unreadable: %w)\", resp.StatusCode, err)","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isBodyReadFailure(err error) bool {\n\tvar netErr net.Error\n\treturn errors.As(err, &netErr) || errors.Is(err, io.ErrUnexpectedEOF)\n}","tryCatchPattern":"err := readResource(ctx, uri)\nif err != nil {\n    if isBodyReadFailure(err) {\n        // secondary transport failure masked the real HTTP status; retry\n        time.Sleep(300 * time.Millisecond)\n        err = readResource(ctx, uri)\n    }\n    if err != nil {\n        return fmt.Errorf(\"repo resource read failed (status masked by body read error): %w\", err)\n    }\n}","preventionTips":["Give the MCP server request contexts deadlines longer than worst-case response latency","Monitor for this message pattern - it indicates the network is dropping responses mid-body","Patch the handler locally to surface resp.StatusCode when the body read fails"],"tags":["go","mcp","network","io","resource","http"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}