apache/shenyu · error · NullPointerException

remoteAddress is null

Error message

remoteAddress is null

What it means

TcpBootstrapServer.getIp extracts the host string from the connection's remote SocketAddress, but first asserts the address is non-null, throwing NullPointerException('remoteAddress is null') otherwise. A null remote address means the gateway never obtained peer information for the TCP connection, so no IP-based processing can continue.

Solutions

  1. Guard the caller: check that the connection/exchange has a non-null remoteAddress before invoking the TCP protocol handling, and drop such connections early.
  2. Log the channel/connection id at error time to find the client or component producing address-less connections.
  3. Verify the TCP listener is set up with the standard Reactor Netty transport so remoteAddress is populated on connect.
  4. Add a connection-level handler that closes sockets without remote address information immediately.

Example fix

// before
String ip = getIp(exchange.getRequest().remoteAddress());
// after
SocketAddress addr = exchange.getRequest().remoteAddress();
if (addr == null) { return; }
String ip = getIp(addr);
Defensive patterns

Strategy: type-guard

Validate before calling

SocketAddress addr = connection.remoteAddress();
if (addr == null) { /* drop connection early */ }

Type guard

static boolean hasRemoteAddress(SocketAddress addr) {
    return addr != null;
}
// usage
if (!hasRemoteAddress(exchange.getRequest().remoteAddress())) { return; }

Try / catch

try {
    String ip = getIp(socketAddress);
} catch (NullPointerException e) {
    if ("remoteAddress is null".equals(e.getMessage())) { /* close/drop the connection */ }
    throw e;
}

Prevention

When it happens

Trigger: The TCP client/connection handling path invokes getIp with the exchange/connection's remoteAddress (called from the client handler) when that attribute is null — typically a connection that was never fully established or was closed before the address was captured.

Common situations: Race conditions where the peer disconnects immediately after connect; custom/derived channel setups that don't populate remoteAddress; connection accepted through an exotic transport that supplies no socket address.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/8a6858b84d49a47e. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-protocol/shenyu-protocol-tcp/src/main/java/org/apache/shenyu/protocol/tcp/TcpBootstrapServer.java:115

        LOG.info("Starting proxy client ={}", serverConn);
        SocketAddress socketAddress = serverConn.channel().remoteAddress();
        ActivityConnectionObserver connectionObserver = new ActivityConnectionObserver("TcpClient");
        eventBus.register(connectionObserver);
        serverConn.onDispose(() -> eventBus.unregister(connectionObserver));
        Mono<Connection> client = connectionContext.getTcpClientConnection(getIp(socketAddress), connectionObserver);
        client.subscribe(
            clientConn -> bridge.bridge(serverConn, clientConn),
            error -> {
                LOG.error("Failed to establish client connection for {}", serverConn, error);
                eventBus.unregister(connectionObserver);
                serverConn.dispose();
            }
        );
    }

    private String getIp(final SocketAddress socketAddress) {
        if (Objects.isNull(socketAddress)) {
            throw new NullPointerException("remoteAddress is null");
        }
        if (socketAddress instanceof InetSocketAddress) {
            return ((InetSocketAddress) socketAddress).getHostString();
        }
        LOG.error("Unsupported SocketAddress type: {}", socketAddress.getClass().getName());
        throw new IllegalArgumentException("Unsupported SocketAddress type: " + socketAddress.getClass().getName());
    }

    /**
     * doOnUpdate.
     *
     * @param removeList removeList
     */
    @Override
    public void removeCommonUpstream(final List<DiscoveryUpstreamData> removeList) {
        eventBus.post(removeList);
    }

View on GitHub (pinned to 567142e072)