{"record":{"id":"ea439b84b1fcb855","repo":"apache/pulsar","slug":"pulsar-client-has-been-closed-can-not-build-looku","errorCode":null,"errorMessage":"Pulsar client has been closed, can not build LookupService when calling get lookup with an url","messagePattern":"Pulsar client has been closed, can not build LookupService when calling get lookup with an url","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java","lineNumber":1783,"sourceCode":"    /**\n     * Only for test.\n     */\n    @VisibleForTesting\n    public CompletableFuture<ClientCnx> getConnection(final String topic) {\n        return getConnection(topic, cnxPool.genRandomKeyToSelectCon()).thenApply(Pair::getLeft);\n    }\n\n    public CompletableFuture<ClientCnx> getConnection(final String topic, final String url) {\n        TopicName topicName = TopicName.get(topic);\n        return getLookup(url).getBroker(topicName)\n                .thenCompose(lookupResult -> getConnection(lookupResult.getLogicalAddress(),\n                        lookupResult.getPhysicalAddress(), cnxPool.genRandomKeyToSelectCon()));\n    }\n\n    public LookupService getLookup(String serviceUrl) {\n        return urlLookupMap.computeIfAbsent(serviceUrl, url -> {\n            if (isClosed()) {\n                throw new IllegalStateException(\"Pulsar client has been closed, can not build LookupService when\"\n                        + \" calling get lookup with an url\");\n            }\n            try {\n                return createLookup(serviceUrl);\n            } catch (PulsarClientException e) {\n                log.warn().attr(\"service\", url).exceptionMessage(e).log(\"Failed to update url to lookup service\");\n                throw new IllegalStateException(\"Failed to update url \" + url);\n            }\n        });\n    }\n\n    public CompletableFuture<ClientCnx> getConnectionToServiceUrl() {\n        if (!lookup.isBinaryProtoLookupService()) {\n            return FutureUtil.failedFuture(new PulsarClientException.InvalidServiceURL(\n                    \"Can't get client connection to HTTP service URL\", null));\n        }\n        InetSocketAddress address = lookup.resolveHost();\n        return getConnection(address, address, cnxPool.genRandomKeyToSelectCon());","sourceCodeStart":1765,"sourceCodeEnd":1801,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java#L1765-L1801","documentation":"getLookup(String serviceUrl) lazily builds a LookupService for a URL. If the client has already been closed, building a new lookup service is impossible, so it throws IllegalStateException asking the caller not to build a lookup after close. This surfaces when code holds a client reference past close() and still queries URL-to-lookup mappings.","triggerScenarios":"Calling client.getLookup(url) (public method) after client.close() has completed, or from another thread while the client is being closed.","commonSituations":"Shutdown hooks or cleanup code that touches the client after close; long-lived caches holding a closed PulsarClient; race between a close() in one thread and getLookup() in another.","solutions":["Ensure getLookup is only called while the client is open — check client.isClosed() first or restructure shutdown ordering.","Create a new PulsarClient instance if lookups are needed after the previous one was closed.","Guard shared client references with lifecycle management so no component uses them post-close."],"exampleFix":"// before\nclient.close();\nLookupService ls = client.getLookup(url); // IllegalStateException\n// after\nif (!client.isClosed()) {\n    LookupService ls = client.getLookup(url);\n}","handlingStrategy":"validation","validationCode":"if (client.isClosed()) {\n    throw new IllegalStateException(\"Refusing getLookup(): client already closed\");\n}\nLookupService ls = client.getLookup(url);","typeGuard":null,"tryCatchPattern":"try {\n    LookupService ls = client.getLookup(url);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"has been closed\")) {\n        client = recreateClient(); // rebuild a fresh client for further lookups\n        ls = client.getLookup(url);\n    } else throw e;\n}","preventionTips":["Check isClosed() before any use of a shared client reference.","Order shutdown so components using getLookup() stop before client.close() runs.","Wrap client access in a lifecycle manager that recreates the client on demand."],"tags":["pulsar","lifecycle","closed-client","illegal-state"],"backgroundTag":"client-already-closed","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"}