{"record":{"id":"7c64fe6dee1de5b8","repo":"alibaba/Sentinel","slug":"client-not-ready","errorCode":"CLIENT_NOT_READY","errorMessage":"client not ready","messagePattern":"client not ready","errorType":"exception","errorClass":"SentinelClusterException","httpStatus":null,"severity":"error","filePath":"sentinel-cluster/sentinel-cluster-client-default/src/main/java/com/alibaba/csp/sentinel/cluster/client/NettyTransportClient.java","lineNumber":210,"sourceCode":"        cleanUp();\n        failConnectedTime.set(0);\n\n        RecordLog.info(\"[NettyTransportClient] Cluster transport client stopped\");\n    }\n\n    private boolean validRequest(Request request) {\n        return request != null && request.getType() >= 0;\n    }\n\n    @Override\n    public boolean isReady() {\n        return channel != null && clientHandler != null && clientHandler.hasStarted();\n    }\n\n    @Override\n    public ClusterResponse sendRequest(ClusterRequest request) throws Exception {\n        if (!isReady()) {\n            throw new SentinelClusterException(ClusterErrorMessages.CLIENT_NOT_READY);\n        }\n        if (!validRequest(request)) {\n            throw new SentinelClusterException(ClusterErrorMessages.BAD_REQUEST);\n        }\n        int xid = getCurrentId();\n        try {\n            request.setId(xid);\n\n            channel.writeAndFlush(request);\n\n            ChannelPromise promise = channel.newPromise();\n            TokenClientPromiseHolder.putPromise(xid, promise);\n\n            if (!promise.await(ClusterClientConfigManager.getRequestTimeout())) {\n                throw new SentinelClusterException(ClusterErrorMessages.REQUEST_TIME_OUT);\n            }\n\n            SimpleEntry<ChannelPromise, ClusterResponse> entry = TokenClientPromiseHolder.getEntry(xid);","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/alibaba/Sentinel/blob/a3f40ba8e900c8489bd520274739f17235a7721c/sentinel-cluster/sentinel-cluster-client-default/src/main/java/com/alibaba/csp/sentinel/cluster/client/NettyTransportClient.java#L192-L228","documentation":"NettyTransportClient.sendRequest() (cluster token client) first checks isReady(): the Netty channel must be non-null, the clientHandler set, and the handler started. If not, it throws SentinelClusterException with code/message CLIENT_NOT_READY. It means the client has not (yet) established its connection to the cluster token server, so no token request can be sent.","triggerScenarios":"Requesting flow tokens (cluster mode) before the Netty client connects to the token server; after the token server restarts or the connection drops and before reconnection; embedding the cluster client without calling start()/init properly (ClusterClientConfigManager state not bound to a live channel).","commonSituations":"Application startup race: requests arrive before the cluster client finishes connecting; token server down or address misconfigured (ClusterClientAssignAssigner / cluster-client config); network partitions causing silent channel loss; failover between embedded and token-server modes.","solutions":["Verify the token server address/port configuration (ClusterStateManager / cluster-client.properties) and that the server is reachable","Wait for client readiness or fail over to local/offline mode: catch SentinelClusterException and check the error type","Check logs for Netty connection failures (TokenClientHandler, connect timeouts)","If the race is at startup, delay or gate traffic until the client has started (check ClusterTransportClient.isReady())"],"exampleFix":"// before\nTokenResult r = tokenService.requestToken(name, count, prioritized);\n\n// after\nTokenResult r;\ntry {\n    r = tokenService.requestToken(name, count, prioritized);\n} catch (SentinelClusterException e) {\n    // fall back to local flow control while cluster client is not ready\n    r = ClusterConstants.checkOkNoJoin ? TokenResult.ok() : localFallback(name, count);\n}","handlingStrategy":"fallback","validationCode":"ClusterTransportClient client = ClusterSpiManager.getClient(); // per version API\nif (client == null || !client.isReady()) {\n    // skip cluster request; use local mode\n}","typeGuard":null,"tryCatchPattern":"try {\n    result = tokenService.requestToken(name, count, prioritized);\n} catch (SentinelClusterException e) {\n    if (ClusterErrorMessages.CLIENT_NOT_READY.equals(e.getMessage())) {\n        result = localModeRequest(name, count); // degrade gracefully\n    } else {\n        throw e;\n    }\n}","preventionTips":["Gate traffic at startup until the cluster client reports isReady()","Monitor token server reachability and configure state change to fail over to local mode","Keep token server address config in cluster-client properties verified by startup checks"],"tags":["cluster","netty","network","token-server","not-ready"],"backgroundTag":null,"analyzedSha":"a3f40ba8e900c8489bd520274739f17235a7721c","analyzedAt":"2026-08-14T11:10:30.678Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}