{"record":{"id":"acf79368de663200","repo":"apache/pulsar","slug":"http-response-body-exceeds-the-configured-maximum","errorCode":null,"errorMessage":"HTTP response body exceeds the configured maximum of ${config.maxResponseBodyBytes} bytes","messagePattern":"HTTP response body exceeds the configured maximum of (.+?) bytes","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/v5/FrameworkHttpClient.java","lineNumber":118,"sourceCode":"     * {@code onBodyPartReceived} aborts the connection and completes the future exceptionally, so the cap\n     * bounds memory rather than being checked after full aggregation.\n     */\n    private final class BoundedResponseHandler extends AsyncCompletionHandlerBase {\n        private long receivedBytes;\n\n        @Override\n        public State onStatusReceived(HttpResponseStatus status) throws Exception {\n            // A new response on this exchange restarts the accumulation, so each response of a redirect\n            // chain is bounded independently (matching the builder reset in the superclass).\n            receivedBytes = 0;\n            return super.onStatusReceived(status);\n        }\n\n        @Override\n        public State onBodyPartReceived(HttpResponseBodyPart content) throws Exception {\n            receivedBytes += content.length();\n            if (receivedBytes > config.maxResponseBodyBytes()) {\n                throw new IOException(\"HTTP response body exceeds the configured maximum of \"\n                        + config.maxResponseBodyBytes() + \" bytes\");\n            }\n            return super.onBodyPartReceived(content);\n        }\n    }\n\n    private org.asynchttpclient.Request toAhcRequest(HttpRequest request) {\n        RequestBuilder builder = new RequestBuilder(request.method().name())\n                .setUrl(request.uri().toString());\n        if (nameResolver != null) {\n            // Share the DNS resolver and its cache with the owning PulsarClient.\n            builder.setNameResolver(nameResolver);\n        }\n\n        request.headers().forEach(builder::setHeader);\n\n        request.body().ifPresent(body -> {\n            if (body instanceof HttpRequest.Bytes bytes) {","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/v5/FrameworkHttpClient.java#L100-L136","documentation":"FrameworkHttpClient's handler accumulates response body bytes in onBodyPartReceived and throws IOException as soon as the running total exceeds config.maxResponseBodyBytes(). This stream-limit guard prevents unbounded memory use from oversized OAuth2/IdP responses. Once tripped, the whole response is aborted.","triggerScenarios":"Any HTTP response from the IdP whose body exceeds the configured maximum — e.g. an unexpectedly huge discovery metadata document, an error page dumped as HTML, a misbehaving gateway streaming endless data, or maxResponseBodyBytes configured too small for a legitimately large response.","commonSituations":"Lowering maxResponseBodyBytes below the real discovery-document size; IdP misconfiguration returning giant HTML error pages; intermediary/proxy injecting large content; legitimate but large JWKS/metadata responses after tenant/key growth.","solutions":["Increase config.maxResponseBodyBytes() to comfortably exceed the expected response size (metadata docs are usually a few KB).","Verify what the endpoint actually returns (curl it) — a giant HTML error page means fix the URL/routing instead.","Check for proxies/interceptors injecting large bodies into the response.","If the response is legitimately huge, consider whether the IdP is misconfigured (e.g. leaking keys repeatedly)."],"exampleFix":"// before\nFrameworkHttpConfig config = FrameworkHttpConfig.builder().maxResponseBodyBytes(1024).build(); // too small\n// after\nFrameworkHttpConfig config = FrameworkHttpConfig.builder().maxResponseBodyBytes(1024 * 1024).build(); // 1 MiB","handlingStrategy":"try-catch","validationCode":"// sanity-check expected response size before configuring the limit\nString body = HttpClient.newHttpClient().send(\n    HttpRequest.newBuilder(URI.create(issuerUrl + \"/.well-known/openid-configuration\")).GET().build(),\n    HttpResponse.BodyHandlers.ofString()).body();\nlong minLimit = body.getBytes(java.nio.charset.StandardCharsets.UTF_8).length * 4; // headroom\nif (maxResponseBodyBytes < minLimit) throw new IllegalStateException(\"Raise maxResponseBodyBytes\");","typeGuard":null,"tryCatchPattern":"try {\n    client = AuthenticationFactoryOAuth2.clientCredentials(issuerUrl, credFile, audience);\n} catch (IOException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"exceeds the configured maximum\")) {\n        throw new RuntimeException(\"Response exceeded maxResponseBodyBytes — raise the limit or fix the endpoint returning oversized bodies\", e);\n    }\n    throw e;\n}","preventionTips":["Set maxResponseBodyBytes with generous headroom over the actual discovery/metadata size (>= 1 MiB is typical).","Curl the endpoints in your environment to see real body sizes before choosing the limit.","Investigate oversized HTML error pages from proxies — fix routing rather than raising limits blindly.","Alert on repeated size-limit trips; they usually indicate a misbehaving intermediary."],"tags":["http","response-size","oauth2","limit-exceeded","pulsar-client"],"backgroundTag":"response-body-too-large","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}