alibaba/Sentinel · error · SentinelClusterException
UNEXPECTED_STATUS
UNEXPECTED_STATUS
Error message
unexpected status
What it means
After a successful promise.await in sendRequest(), the code looks up the completed entry by xid in TokenClientPromiseHolder. If the entry or its response value is null, it throws SentinelClusterException(UNEXPECTED_STATUS) with the source comment 'Should not go through here'. It fires when the promise completed (usually exceptionally, e.g. channel closed) without a response ever being stored — a rare internal inconsistency path.
Source
Thrown at sentinel-cluster/sentinel-cluster-client-default/src/main/java/com/alibaba/csp/sentinel/cluster/client/NettyTransportClient.java:231
throw new SentinelClusterException(ClusterErrorMessages.BAD_REQUEST);
}
int xid = getCurrentId();
try {
request.setId(xid);
channel.writeAndFlush(request);
ChannelPromise promise = channel.newPromise();
TokenClientPromiseHolder.putPromise(xid, promise);
if (!promise.await(ClusterClientConfigManager.getRequestTimeout())) {
throw new SentinelClusterException(ClusterErrorMessages.REQUEST_TIME_OUT);
}
SimpleEntry<ChannelPromise, ClusterResponse> entry = TokenClientPromiseHolder.getEntry(xid);
if (entry == null || entry.getValue() == null) {
// Should not go through here.
throw new SentinelClusterException(ClusterErrorMessages.UNEXPECTED_STATUS);
}
return entry.getValue();
} finally {
TokenClientPromiseHolder.remove(xid);
}
}
private int getCurrentId() {
int pre, next;
do {
pre = idGenerator.get();
next = pre >= MAX_ID ? MIN_ID : pre + 1;
} while (!idGenerator.compareAndSet(pre, next));
return next;
}
/*public CompletableFuture<ClusterResponse> sendRequestAsync(ClusterRequest request) {
// Uncomment this when min target JDK is 1.8.View on GitHub (pinned to a3f40ba8e9)
Solutions
- Treat like other cluster failures: catch SentinelClusterException and degrade to local flow control
- Check client-server connectivity and TokenClientHandler logs for the underlying channel error
- Upgrade Sentinel — later versions hardened promise failure handling in NettyTransportClient/TokenClientPromiseHolder
- Ensure only one event loop touches the promise holder (no custom client modifications)
Example fix
// before
TokenResult r = tokenService.requestToken(name, count, prioritized);
// after
TokenResult r;
try {
r = tokenService.requestToken(name, count, prioritized);
} catch (SentinelClusterException e) {
logger.warn("cluster request failed: {}", e.getMessage());
r = new TokenResult(TokenResultStatus.FAIL); // local fallback decision
} Defensive patterns
Strategy: fallback
Try / catch
try {
result = tokenService.requestToken(name, count, prioritized);
} catch (SentinelClusterException e) {
logger.warn("cluster transport anomaly: {}", e.getMessage());
result = localModeRequest(name, count);
} Prevention
- Treat UNEXPECTED_STATUS as a connection-churn symptom: check TokenClientHandler logs
- Keep the Sentinel version current — this 'should not happen' path has been hardened over releases
- Degrade to local flow control on any SentinelClusterException in the request path
When it happens
Trigger: The channel fails/closes after writeAndFlush but before the response arrives — the promise is failed (completing the await) while TokenClientHandler never put a ClusterResponse for that xid; concurrent disconnect racing an in-flight request.
Common situations: Token server or connection dropping mid-request; Netty pipeline exceptions; seen intermittently during token-server restarts or network flaps.
Related errors
AI-assisted analysis of alibaba/Sentinel@a3f40ba8e9 (2026-08-14).
Data as JSON: /api/errors/c37f45106a0749cd.
Report an issue: GitHub.