{"record":{"id":"14fb4e60d96db8e0","repo":"Hmbown/CodeWhale","slug":"oauth-http-response-body-exceeds-max-oauth-http-response","errorCode":null,"errorMessage":"OAuth HTTP response body exceeds {MAX_OAUTH_HTTP_RESPONSE_BODY_BYTES} bytes","messagePattern":"OAuth HTTP response body exceeds (.+?) bytes","errorType":"validation","errorClass":"anyhow","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/oauth.rs","lineNumber":322,"sourceCode":"            let mut response = self\n                .client\n                .execute(\n                    request,\n                    matches!(redirect_policy, OAuthHttpRedirectPolicy::Follow),\n                )\n                .await\n                .map_err(|error| -> OAuthHttpClientError { error.into() })?;\n            let status = response.status();\n            let version = response.version();\n            let headers = response.headers().clone();\n            let mut body = Vec::new();\n            while let Some(chunk) = response\n                .chunk()\n                .await\n                .map_err(|error| Box::new(error) as OAuthHttpClientError)?\n            {\n                if chunk.len() > MAX_OAUTH_HTTP_RESPONSE_BODY_BYTES - body.len() {\n                    return Err(anyhow!(\n                        \"OAuth HTTP response body exceeds {MAX_OAUTH_HTTP_RESPONSE_BODY_BYTES} bytes\"\n                    )\n                    .into());\n                }\n                body.extend_from_slice(&chunk);\n            }\n            if is_token_request {\n                *self\n                    .last_token_response\n                    .lock()\n                    .unwrap_or_else(std::sync::PoisonError::into_inner) =\n                    Some(TokenEndpointReceipt::from_response(status, &headers, &body));\n            }\n            let mut builder = oauth2::http::Response::builder()\n                .status(status)\n                .version(version);\n            for (name, value) in &headers {\n                builder = builder.header(name, value);","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/oauth.rs#L304-L340","documentation":"The OAuth HTTP client enforces a hard cap (MAX_OAUTH_HTTP_RESPONSE_BODY_BYTES) on how many bytes it will read from an OAuth endpoint's response body. While streaming the body chunk-by-chunk, if the next chunk would push the accumulated body past the limit, the read is aborted and this error is returned. This protects the client from memory exhaustion caused by a malicious or misbehaving OAuth server returning an oversized response.","triggerScenarios":"Any OAuth HTTP exchange (token request, discovery, JWKS fetch, etc.) where the server's response body length exceeds MAX_OAUTH_HTTP_RESPONSE_BODY_BYTES; detected inside the response.chunk() streaming loop after the accumulated body plus the next chunk exceeds the limit.","commonSituations":"Pointing the OAuth discovery/authorization metadata URL at a misconfigured proxy or portal that returns a large HTML error/login page instead of a small JSON document; a compromised or rogue MCP server deliberately flooding the response; a reverse proxy returning a huge interstitial page.","solutions":["Verify the OAuth issuer/discovery URL points at the real OAuth server, not a proxy or login page returning large HTML","Inspect what the server actually returns (curl the URL) and fix the server-side response","If the limit is genuinely too small for a legitimate deployment, raise MAX_OAUTH_HTTP_RESPONSE_BODY_BYTES deliberately"],"exampleFix":"// before: metadata URL behind a captive portal returning an HTML page\n\"discovery_url\": \"https://portal.example.com/.well-known/oauth-authorization-server\"\n// after: point directly at the real issuer\n\"discovery_url\": \"https://auth.example.com/.well-known/oauth-authorization-server\"","handlingStrategy":"validation","validationCode":"let url = discovery_url;\nif !url.starts_with(\"https://\") || url.contains(\"portal\") {\n    // verify the endpoint actually returns a small JSON document before use\n}\n// optionally: HEAD/GET the URL and check Content-Length < MAX_OAUTH_HTTP_RESPONSE_BODY_BYTES","typeGuard":null,"tryCatchPattern":"match oauth_exchange_result {\n    Err(e) if e.to_string().contains(\"exceeds\") => {\n        // treat as untrusted/misbehaving OAuth endpoint; refuse to proceed and log\n    }\n    other => other?,\n}","preventionTips":["Point discovery/token URLs directly at the real OAuth issuer, never at a portal or proxy page","Curl each configured OAuth URL once during setup and confirm it returns small JSON","Never disable or blindly raise the body cap to work around a bad endpoint"],"tags":["oauth","http","response-size-limit","mcp"],"backgroundTag":"payload-too-large","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}