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

  1. Increase the client's request timeout so it does not drop the connection before the TC replies
  2. Check server message executor saturation (long task processing delays responses past channel lifetime)
  3. Verify clients are not being prematurely disconnected by idle/heartbeat settings
  4. 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

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


AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14). Data as JSON: /api/errors/f2bf6281a3e3483a. Report an issue: GitHub.