{"id":"1fc18f2f4e30cc0d","repo":"apache/kafka","slug":"attempt-to-retrieve-value-from-future-which-hasn-t","errorCode":null,"errorMessage":"Attempt to retrieve value from future which hasn't successfully completed","messagePattern":"Attempt to retrieve value from future which hasn't successfully completed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/RequestFuture.java","lineNumber":74,"sourceCode":"     * @return true if the response is ready, false otherwise\n     */\n    public boolean isDone() {\n        return result.get() != INCOMPLETE_SENTINEL;\n    }\n\n    public boolean awaitDone(long timeout, TimeUnit unit) throws InterruptedException {\n        return completedLatch.await(timeout, unit);\n    }\n\n    /**\n     * Get the value corresponding to this request (only available if the request succeeded)\n     * @return the value set in {@link #complete(Object)}\n     * @throws IllegalStateException if the future is not complete or failed\n     */\n    @SuppressWarnings(\"unchecked\")\n    public T value() {\n        if (!succeeded())\n            throw new IllegalStateException(\"Attempt to retrieve value from future which hasn't successfully completed\");\n        return (T) result.get();\n    }\n\n    /**\n     * Check if the request succeeded;\n     * @return true if the request completed and was successful\n     */\n    public boolean succeeded() {\n        return isDone() && !failed();\n    }\n\n    /**\n     * Check if the request failed.\n     * @return true if the request completed with a failure\n     */\n    public boolean failed() {\n        return result.get() instanceof RuntimeException;\n    }","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/RequestFuture.java#L56-L92","documentation":"IllegalStateException thrown by RequestFuture.value() when the caller asks for the result before the future has completed successfully. RequestFuture is an internal ad-hoc future used by the consumer's request/response machinery; its value is only meaningful after complete(value) has been called. Calling value() on an incomplete or failed future is a programming error in the consumer internals, not a recoverable network condition.","triggerScenarios":"Raised when value() is invoked while isDone() is false or while failed() is true. Occurs only inside consumer internal code that mishandles the future lifecycle (e.g. reads value before awaiting completion, or after the future was completed exceptionally). User code does not normally hold a RequestFuture reference.","commonSituations":"Indicates a bug in the consumer internals or in custom code extending AbstractCoordinator / RequestFutureListener that calls value() at the wrong point. Not caused by config or environment. Rarely seen in stock kafka-clients; if observed it warrants a bug report against the version in use.","solutions":["If extending consumer internals, always gate value() behind an succeeded() / awaitDone() check.","Upgrade kafka-clients: this usually indicates an internal state-machine bug that has likely been fixed.","Capture the stack trace and report against the Kafka JIRA with the consumer config and broker version."],"exampleFix":"// before\nRequestFuture<Foo> f = sendRequest();\nFoo v = f.value();\n\n// after\nRequestFuture<Foo> f = sendRequest();\nif (f.awaitDone(30, TimeUnit.SECONDS) && f.succeeded()) {\n    Foo v = f.value();\n} else if (f.failed()) {\n    throw f.exception();\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Never call RequestFuture.value() without first narrowing on state.\njava.util.function.Predicate<RequestFuture<?>> isUsable =\n    f -> f.isDone() && !f.failed();\nif (isUsable.test(future)) {\n    Object v = future.value();\n}\n// or, with the public API surface users actually see:\njava.util.concurrent.Future<T> f = ...;\nif (f.isDone() && !f.isCancelled()) {\n    T v = f.get(); // throws ExecutionException for failures instead of IllegalStateException\n}","tryCatchPattern":"try {\n    return future.value();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"hasn't successfully completed\")) {\n        // programming error — do not retry, fix the call site\n        throw new IllegalStateException(\"Caller bug: accessed RequestFuture value before completion\", e);\n    }\n    throw e;\n}","preventionTips":["Always guard future.value() with future.succeeded() (or isDone() && !failed()) at the call site.","Prefer composing futures via onSuccess/onFailure listeners over blocking then unwrapping; it eliminates the failure mode entirely.","If you must block, use awaitDone(timeout, unit) and then re-check succeeded() before calling value().","Add a unit test that asserts every value() call site in your code is preceded by a succeeded() check.","Treat the IllegalStateException from value() as a programmer error, not a runtime contingency — never catch-and-retry it blindly."],"tags":["kafka","consumer","internal","future","illegal-state"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}