{"id":"da95db245a9de06f","repo":"apache/kafka","slug":"failed-to-close-kafka-share-consumer","errorCode":null,"errorMessage":"Failed to close Kafka share consumer","messagePattern":"Failed to close Kafka share consumer","errorType":"exception","errorClass":"KafkaException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareConsumerImpl.java","lineNumber":1058,"sourceCode":"        // the reaper nor the background event queue were constructed, so check them first to avoid NPE.\n        if (backgroundEventReaper != null && backgroundEventQueue != null)\n            backgroundEventReaper.reap(backgroundEventQueue);\n\n        closeQuietly(kafkaShareConsumerMetrics, \"kafka share consumer metrics\", firstException);\n        closeQuietly(asyncConsumerMetrics, \"kafka async consumer metrics\", firstException);\n        closeQuietly(shareFetchMetricsManager, \"kafka share consumer fetch metrics\", firstException);\n        closeQuietly(metrics, \"consumer metrics\", firstException);\n        closeQuietly(deserializers, \"consumer deserializers\", firstException);\n        clientTelemetryReporter.ifPresent(reporter -> closeQuietly(reporter, \"consumer telemetry reporter\", firstException));\n\n        AppInfoParser.unregisterAppInfo(CONSUMER_JMX_PREFIX, clientId, metrics);\n        log.debug(\"Kafka share consumer has been closed\");\n        Throwable exception = firstException.get();\n        if (exception != null && !swallowException) {\n            if (exception instanceof InterruptException) {\n                throw (InterruptException) exception;\n            }\n            throw new KafkaException(\"Failed to close Kafka share consumer\", exception);\n        }\n    }\n\n    private void stopFindCoordinatorOnClose() {\n        if (applicationEventHandler == null) {\n            return;\n        }\n        log.debug(\"Stop finding coordinator during consumer close\");\n        applicationEventHandler.add(new StopFindCoordinatorOnCloseEvent());\n    }\n\n    private Timer createTimerForCloseRequests(Duration timeout) {\n        // this.time could be null if an exception occurs in constructor prior to setting the this.time field\n        final Time time = (this.time == null) ? Time.SYSTEM : this.time;\n        return time.timer(Math.min(timeout.toMillis(), requestTimeoutMs));\n    }\n\n    /**","sourceCodeStart":1040,"sourceCodeEnd":1076,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareConsumerImpl.java#L1040-L1076","documentation":"Thrown by ShareConsumerImpl.close(...) (line 1058) as the wrapper exception when one of the sub-components throws during shutdown and swallowException is false. The close sequence aggregates firstException across metrics, fetch metrics, deserializers, telemetry reporter, and the network client via closeQuietly; if any fails, the original is chained as the cause of this KafkaException. It signals that shutdown did not complete cleanly even though the consumer is functionally closed.","triggerScenarios":"Closing a KafkaShareConsumer while the network thread or background event queue raises an exception (e.g. InterruptException from a shutdown hook interrupting mid-flush, or an acknowledgement commit still in flight). Also triggered when a deserializer.close() or metrics reporter.close() throws, and the close path is not allowed to swallow it.","commonSituations":"JVM shutdown hooks interrupting the consumer during graceful close; broker disconnection while the consumer is flushing acknowledgements on close; misbehaving custom Deserializer or MeterRegistry integration whose close() throws; running under a framework that wraps close() in a timeout and forcibly interrupts the thread.","solutions":["Inspect the chained cause (ex.getCause()) — it identifies which sub-component failed (network, deserializer, telemetry reporter).","Ensure graceful shutdown: stop the poll loop and call close() with an adequate timeout before the JVM/ container sends SIGTERM/SIGINT.","Fix or replace custom Deserializer/Metric/Telemetry components whose close() throws.","If the interrupt during close is expected in your runtime, catch InterruptException and KafkaException at the call site and log, but do not ignore the cause."],"exampleFix":"// before\nconsumer.close();\n\n// after\ntry {\n    consumer.close(Duration.ofSeconds(30));\n} catch (org.apache.kafka.common.KafkaException e) {\n    log.warn(\"Share consumer close failed: {}\", e.getCause().getMessage());\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"// close() is best-effort: capture but never let close failures mask the primary exception.\nThrowable primary = null;\ntry {\n    /* main work */\n} catch (Throwable t) {\n    primary = t;\n    throw t;\n} finally {\n    try {\n        consumer.close(java.time.Duration.ofSeconds(10));\n    } catch (org.apache.kafka.common.KafkaException e) {\n        log.warn(\"Error closing share consumer\", e);\n        if (primary == null) throw e;\n        primary.addSuppressed(e);\n    }\n}","preventionTips":["Wrap close() in try/finally and log the wrapped exception, but never let it shadow the primary exception from the try block.","Use a generous close timeout so pending acknowledgements can be flushed; tight timeouts increase the chance of this exception.","Ensure the broker/coordinator is reachable during shutdown; network errors during close are a common root cause."],"tags":["share-consumer","close","shutdown","kafka-client"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}