Skip to content

Commit 2626e28

Browse files
chensishangclaude
andauthored
Fix misleading NPE when request parameter is not Serializable (#16299)
* Fix misleading NPE when request parameter is not Serializable When a Dubbo service is called with non-serializable parameters, the invocation deserialization fails silently and `path` becomes null. This null path is then passed to GroupServiceKeyCache which uses a ConcurrentHashMap that does not accept null keys, resulting in a confusing NullPointerException. Added a null check for `path` in DubboProtocol.getInvoker() to throw a clear RemotingException with a meaningful message pointing users to the actual cause (non-serializable parameters). Fixes #16293 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Make null path error message generic to avoid misleading diagnosis --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b16c837 commit 2626e28

2 files changed

Lines changed: 27 additions & 0 deletions

File tree

dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,15 @@ Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException
290290
boolean isStubServiceInvoke;
291291
int port = channel.getLocalAddress().getPort();
292292
String path = (String) inv.getObjectAttachmentWithoutConvert(PATH_KEY);
293+
if (path == null) {
294+
throw new RemotingException(
295+
channel,
296+
"Service path is missing from the invocation, which indicates the invocation metadata is "
297+
+ "missing or corrupted. Possible causes include a request decode failure "
298+
+ "(e.g. parameter types that failed to deserialize), an incompatible protocol "
299+
+ "version, or a custom codec/invocation implementation that does not set the path, "
300+
+ "channel: " + channel.getRemoteAddress() + " --> " + channel.getLocalAddress());
301+
}
293302

294303
// if it's stub service on client side(after enable stubevent, usually is set up onconnect or ondisconnect
295304
// method)

dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.apache.dubbo.common.URL;
2020
import org.apache.dubbo.common.extension.ExtensionLoader;
2121
import org.apache.dubbo.common.utils.NetUtils;
22+
import org.apache.dubbo.remoting.Channel;
23+
import org.apache.dubbo.remoting.RemotingException;
2224
import org.apache.dubbo.rpc.Invocation;
2325
import org.apache.dubbo.rpc.Invoker;
2426
import org.apache.dubbo.rpc.Protocol;
@@ -38,6 +40,7 @@
3840
import org.apache.dubbo.rpc.protocol.dubbo.support.Type;
3941
import org.apache.dubbo.rpc.service.EchoService;
4042

43+
import java.net.InetSocketAddress;
4144
import java.util.Arrays;
4245
import java.util.HashMap;
4346
import java.util.List;
@@ -281,6 +284,21 @@ public void testReturnNonSerialized() {
281284
}
282285
}
283286

287+
@Test
288+
void testGetInvokerThrowsOnNullPath() {
289+
DubboProtocol dubboProtocol = DubboProtocol.getDubboProtocol();
290+
Channel channel = Mockito.mock(Channel.class);
291+
InetSocketAddress localAddress = new InetSocketAddress("127.0.0.1", 20880);
292+
InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 12345);
293+
Mockito.when(channel.getLocalAddress()).thenReturn(localAddress);
294+
Mockito.when(channel.getRemoteAddress()).thenReturn(remoteAddress);
295+
296+
Invocation inv = Mockito.mock(Invocation.class);
297+
Mockito.when(inv.getObjectAttachmentWithoutConvert("path")).thenReturn(null);
298+
299+
Assertions.assertThrows(RemotingException.class, () -> dubboProtocol.getInvoker(channel, inv));
300+
}
301+
284302
@Disabled
285303
@Test
286304
void testRemoteApplicationName() throws Exception {

0 commit comments

Comments
 (0)