apache/incubator-seata · error · RuntimeException
channel is error.
Error message
channel is error.
What it means
Server-side error from AbstractNettyRemotingServer.sendAsyncResponse: when replying to a client request, the TC could not find the channel to answer on. For non-heartbeat messages it re-resolves the channel via ChannelManager.getSameClientChannel(channel); a null result means the client behind that channel is no longer registered, so the response is undeliverable.
Source
Thrown at core/src/main/java/org/apache/seata/core/rpc/netty/AbstractNettyRemotingServer.java:114
super.sendAsync(channel, rpcMessage);
}
@Override
public void sendAsyncResponse(RpcMessage rpcMessage, Channel channel, Object msg) {
Channel clientChannel = channel;
if (!(msg instanceof HeartbeatMessage)) {
clientChannel = ChannelManager.getSameClientChannel(channel);
}
if (clientChannel != null) {
RpcMessage rpcMsg = buildResponseMessage(
rpcMessage,
msg,
msg instanceof HeartbeatMessage
? ProtocolConstants.MSGTYPE_HEARTBEAT_RESPONSE
: ProtocolConstants.MSGTYPE_RESPONSE);
super.sendAsync(clientChannel, rpcMsg);
} else {
throw new RuntimeException("channel is error.");
}
}
@Override
public void registerProcessor(int messageType, RemotingProcessor processor, ExecutorService executor) {
Pair<RemotingProcessor, ExecutorService> pair = new Pair<>(processor, executor);
this.processorTable.put(messageType, pair);
}
/**
* Gets listen port.
*
* @return the listen port
*/
public int getListenPort() {
return serverBootstrap.getListenPort();
}
View on GitHub (pinned to e01f97c6db)
Solutions
- Increase the client's request timeout so it does not drop the connection before the TC replies
- Check server message executor saturation (long task processing delays responses past channel lifetime)
- Verify clients are not being prematurely disconnected by idle/heartbeat settings
- The dropped response is usually recoverable: the client retries or re-registers; monitor for repeated occurrences rather than one-offs
Defensive patterns
Strategy: try-catch
Validate before calling
Channel target = (msg instanceof HeartbeatMessage) ? channel : ChannelManager.getSameClientChannel(channel);
if (target == null) { /* client gone: skip response, log */ return; } Try / catch
catch (RuntimeException e) {
if ("channel is error.".equals(e.getMessage())) {
// response undeliverable: log clientId and rely on client retry/timeout
}
} Prevention
- Set client request timeouts above worst-case server processing time
- Keep server message executors from saturating (bounded queues, monitoring)
- Expect occasional lost responses; make clients idempotent/retrying
When it happens
Trigger: The TC processing an RM/TM request and calling sendAsyncResponse after the requesting client has disconnected or been unregistered (channel closed between request receipt and response send); heartbeat messages bypass the lookup and use the inbound channel directly.
Common situations: Client timeout shorter than server processing time, so the client closes the connection before the response; client crash/restart mid-request; channel idle-evicted while its messages were still queued on the server executor.
Related errors
- rm client is not connected. dbkey:{resourceId},clientId:{cli
- client is not connected
- Server start failed, the listen port: %s
- unknown dbtype:{dbType}
- 0109
AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14).
Data as JSON: /api/errors/f2bf6281a3e3483a.
Report an issue: GitHub.