{"id":"0ddc90b085b2b1bd","repo":"apache/kafka","slug":"client-was-shutdown-before-response-was-read","errorCode":null,"errorMessage":"Client was shutdown before response was read","messagePattern":"Client was shutdown before response was read","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/NetworkClientUtils.java","lineNumber":120,"sourceCode":"     */\n    public static ClientResponse sendAndReceive(KafkaClient client, ClientRequest request, Time time) throws IOException {\n        try {\n            client.send(request, time.milliseconds());\n            while (client.active()) {\n                List<ClientResponse> responses = client.poll(Long.MAX_VALUE, time.milliseconds());\n                for (ClientResponse response : responses) {\n                    if (response.requestHeader().correlationId() == request.correlationId()) {\n                        if (response.wasDisconnected()) {\n                            throw new IOException(\"Connection to \" + response.destination() + \" was disconnected before the response was read\");\n                        }\n                        if (response.versionMismatch() != null) {\n                            throw response.versionMismatch();\n                        }\n                        return response;\n                    }\n                }\n            }\n            throw new IOException(\"Client was shutdown before response was read\");\n        } catch (DisconnectException e) {\n            if (client.active())\n                throw e;\n            else\n                throw new IOException(\"Client was shutdown before response was read\");\n\n        }\n    }\n\n    /**\n     * Check if the code is disconnected and unavailable for immediate reconnection (i.e. if it is in\n     * reconnect backoff window following the disconnect).\n     */\n    public static boolean isUnavailable(KafkaClient client, Node node, Time time) {\n        return client.connectionFailed(node) && client.connectionDelay(node, time.milliseconds()) > 0;\n    }\n\n    /**","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/NetworkClientUtils.java#L102-L138","documentation":"Thrown as IOException by NetworkClientUtils.sendAndReceive when the polling loop exits because client.active() returned false before a matching response arrived. Unlike the disconnected-response case, here the channel was not flagged disconnected; the blocking call simply observed that the NetworkClient had transitioned out of ACTIVE state (initiateClose/close). It indicates the client was shut down while a blocking request was still outstanding.","triggerScenarios":"sendAndReceive sends the request, then loops while client.active() is true; the loop terminates with no matching response once active() flips false. This happens when close()/initiateClose() is invoked from another thread during the blocking call. The IOException distinguishes this case from a network-level disconnect.","commonSituations":"Concurrent close(): one thread blocks in sendAndReceive while another closes the client (e.g. shutdown hook, Spring bean destruction, timeout-driven cleanup); AdminClient.close() racing with an in-flight Admin call; producer.close() during a send callback that itself calls back into the client.","solutions":["Do not close the client from another thread while a blocking call is in flight; sequence shutdown after outstanding calls drain.","Use non-blocking APIs (KafkaProducer.send with Callback, Admin result futures) instead of sendAndReceive where possible.","Catch IOException at the call site and surface it as 'client shutting down' rather than a network error.","Ensure shutdown hooks / bean destroy order waits for in-flight requests before closing the client."],"exampleFix":"// before (blocking call racing with close in another thread)\nnew Thread(() -> admin.close()).start();\nresponse = NetworkClientUtils.sendAndReceive(client, request, time);\n// after (close only after blocking calls drain)\n// caller ensures no in-flight blocking call before invoking close()\nadmin.close(Duration.ofSeconds(10));","handlingStrategy":"try-catch","validationCode":"// Pre-check: if the client is already inactive, fail fast instead of entering sendAndReceive.\nif (!client.active()) {\n    throw new java.io.IOException(\n        \"NetworkClient inactive; cannot sendAndReceive. Rebuild the client before retrying.\");\n}","typeGuard":"// Treat 'active' as a runtime capability check.\npublic static boolean canSendAndReceive(KafkaClient client) {\n    return client != null && client.active();\n}","tryCatchPattern":"try {\n    return NetworkClientUtils.sendAndReceive(client, request, time);\n} catch (java.io.IOException e) {\n    if (\"Client was shutdown before response was read\".equals(e.getMessage())) {\n    // The client was closed concurrently. The request is lost. Do NOT retry on this client;\n    // build a new NetworkClient and re-issue the request from scratch.\n    return reissueOnFreshClient(request);\n    }\n    throw e;\n}","preventionTips":["This fires when initiateClose()/close() races with an in-flight sendAndReceive — a lifecycle bug, not a network blip.","Own the client from a single component; serialize shutdown vs. work via a flag or queue.","On shutdown, drain in-flight requests (producer.flush(), consumer.close()) before calling close().","Do not retry on the same client instance; it cannot be reactivated."],"tags":["lifecycle","shutdown","concurrency","blocking"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}