apache/incubator-seata · error · IOException
client is not connected
Error message
client is not connected
What it means
Server-side error from AbstractNettyRemotingServer.sendSyncRequest(Channel, Object): the caller passed a null channel, so the TC refuses to build and send the sync RPC. It is a programming/lookup bug on the server side rather than a network condition — the channel reference must be obtained (and non-null) before this overload is used.
Source
Thrown at core/src/main/java/org/apache/seata/core/rpc/netty/AbstractNettyRemotingServer.java:84
serverBootstrap = new NettyServerBootstrap(nettyServerConfig);
serverBootstrap.setChannelHandlers(new ServerHandler());
}
@Override
public Object sendSyncRequest(String resourceId, String clientId, Object msg, boolean tryOtherApp)
throws TimeoutException, IOException {
Channel channel = ChannelManager.getChannel(resourceId, clientId, tryOtherApp);
if (channel == null) {
throw new IOException("rm client is not connected. dbkey:" + resourceId + ",clientId:" + clientId);
}
RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_SYNC);
return super.sendSync(channel, rpcMessage, NettyServerConfig.getRpcRequestTimeout());
}
@Override
public Object sendSyncRequest(Channel channel, Object msg) throws TimeoutException, IOException {
if (channel == null) {
throw new IOException("client is not connected");
}
RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_SYNC);
return super.sendSync(channel, rpcMessage, NettyServerConfig.getRpcRequestTimeout());
}
@Override
public void sendAsyncRequest(Channel channel, Object msg) throws IOException {
if (channel == null) {
throw new IOException("client is not connected");
}
RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_ONEWAY);
super.sendAsync(channel, rpcMessage);
}
@Override
public void sendAsyncResponse(RpcMessage rpcMessage, Channel channel, Object msg) {
Channel clientChannel = channel;
if (!(msg instanceof HeartbeatMessage)) {View on GitHub (pinned to e01f97c6db)
Solutions
- Fetch the channel via ChannelManager with the resourceId/clientId overload that throws a descriptive error, instead of managing channels manually
- Guard with a null check and re-resolve the channel before retrying the send
- If writing a custom processor, follow the existing processors: they resolve the channel from the incoming message context, never cache it
Example fix
// before
server.sendSyncRequest(channel, request); // channel may be null
// after
Channel channel = ChannelManager.getChannel(resourceId, clientId, tryOtherApp);
if (channel == null || !channel.isActive()) {
throw new IOException("client is not connected: " + clientId);
}
server.sendSyncRequest(channel, request); Defensive patterns
Strategy: validation
Validate before calling
Channel ch = ChannelManager.getChannel(resourceId, clientId, tryOtherApp);
if (ch == null) throw new IOException("client not connected: " + clientId);
server.sendSyncRequest(ch, msg); Try / catch
catch (IOException e) {
if ("client is not connected".equals(e.getMessage())) { /* re-resolve channel and retry once */ }
} Prevention
- Always resolve the channel through ChannelManager immediately before sending
- Check isActive() in addition to non-null
- Avoid custom channel caching in server-side processors
When it happens
Trigger: Calling sendSyncRequest((Channel) null, msg) directly, or passing a channel variable that a prior lookup (e.g. ChannelManager.getChannel) returned null for without a null check.
Common situations: Custom server-side code or a fork of seata-server that fetches a client channel and forwards it without checking; races where the channel was closed and nulled between fetch and send.
Related errors
- 0109
- rm client is not connected. dbkey:{resourceId},clientId:{cli
- channel is error.
- Server start failed, the listen port: %s
- unknown dbtype:{dbType}
AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14).
Data as JSON: /api/errors/3886efd86abc31ba.
Report an issue: GitHub.