{"record":{"id":"5bf0bdacdd71926d","repo":"apache/dubbo","slug":"rpc-cluster-invoker-for-getinterface-on-consum","errorCode":null,"errorMessage":"Rpc cluster invoker for {getInterface()} on consumer {NetUtils.getLocalHost()} use dubbo version {Version.getVersion()} is now destroyed! Can not invoke any more.","messagePattern":"Rpc cluster invoker for (.+?) on consumer (.+?) use dubbo version (.+?) is now destroyed! Can not invoke any more\\.","errorType":"exception","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java","lineNumber":374,"sourceCode":"        InvocationProfilerUtils.releaseDetailProfiler(invocation);\n\n        checkInvokers(invokers, invocation);\n\n        LoadBalance loadbalance = initLoadBalance(invokers, invocation);\n        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);\n\n        InvocationProfilerUtils.enterDetailProfiler(\n                invocation, () -> \"Cluster \" + this.getClass().getName() + \" invoke.\");\n        try {\n            return doInvoke(invocation, invokers, loadbalance);\n        } finally {\n            InvocationProfilerUtils.releaseDetailProfiler(invocation);\n        }\n    }\n\n    protected void checkWhetherDestroyed() {\n        if (destroyed.get()) {\n            throw new RpcException(\n                    \"Rpc cluster invoker for \" + getInterface() + \" on consumer \" + NetUtils.getLocalHost()\n                            + \" use dubbo version \" + Version.getVersion()\n                            + \" is now destroyed! Can not invoke any more.\");\n        }\n    }\n\n    @Override\n    public String toString() {\n        return getInterface() + \" -> \" + getUrl().toString();\n    }\n\n    protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {\n        if (CollectionUtils.isEmpty(invokers)) {\n            throw new RpcException(\n                    RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER,\n                    \"Failed to invoke the method \"\n                            + RpcUtils.getMethodName(invocation) + \" in the service \"\n                            + getInterface().getName()","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java#L356-L392","documentation":"Thrown by AbstractClusterInvoker.checkWhetherDestroyed() when the cluster invoker's 'destroyed' AtomicBoolean is true. The cluster invoker wraps a Directory and performs the cluster strategy (failover/failfast/etc.); once destroyed it rejects all further invokes. This is the cluster-level counterpart to the directory-destroyed error.","triggerScenarios":"Invoking through a Dubbo service reference whose ClusterInvoker has been destroyed — after ReferenceConfig.destroy(), Spring container shutdown, or the consumer being unsubscribed. checkWhetherDestroyed() is called at the start of each cluster invoke and on each failover retry.","commonSituations":"Application shutdown while business threads still call the service; a cached/stale service proxy used after its reference was destroyed; hot redeploy replacing the reference; in-flight failover retries where the invoker is destroyed mid-retry.","solutions":["Stop issuing RPCs before destroying the reference; coordinate shutdown so callers drain first.","Guard late-lifecycle calls with clusterInvoker.isDestroyed() (or check the reference) before invoking.","Fix shutdown ordering so the Dubbo module/reference is destroyed only after all caller threads are stopped."],"exampleFix":"// before: invoke after destroy\nreferenceConfig.destroy();\nservice.foo(); // checkWhetherDestroyed() throws\n\n// after: guard\nif (!clusterInvoker.isDestroyed()) {\n    service.foo();\n}","handlingStrategy":"validation","validationCode":"// Guard against invoking a destroyed cluster invoker\nif (clusterInvoker.isDestroyed()) {\n    return null; // or throw a domain-specific exception\n}\nreturn clusterInvoker.invoke(invocation);","typeGuard":null,"tryCatchPattern":"try {\n    return clusterInvoker.invoke(invocation);\n} catch (RpcException e) {\n    if (e.getMessage().contains(\"is now destroyed\")) {\n        // reference torn down; degrade gracefully, do not retry\n        log.warn(\"Cluster invoker destroyed; skipping call\");\n        return fallback();\n    }\n    throw e;\n}","preventionTips":["Stop submitting RPCs before destroying the reference/container.","Check ClusterInvoker.isDestroyed() in shutdown-sensitive code paths.","Coordinate shutdown ordering so callers quiesce before Dubbo tears down."],"tags":["cluster","lifecycle","consumer","failover"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}