apache/dubbo · error · IllegalStateException
Stream method could not be overloaded.There are ${streamMeth
Error message
Stream method could not be overloaded.There are ${streamMethodCount} stream method signatures. method(${methodName}) What it means
ReflectionServiceDescriptor.initMethods() groups methods by name and counts how many resolve to SERVER_STREAM or BI_STREAM. Dubbo forbids overloading streaming methods of the same name because the dispatch layer keys on method name and cannot disambiguate two streaming variants. If more than one streaming overload exists for a name, registration is aborted at service-descriptor build time.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ReflectionServiceDescriptor.java:90
MethodDescriptor methodDescriptor = new ReflectionMethodDescriptor(method);
List<MethodDescriptor> methodModels = methods.computeIfAbsent(method.getName(), (k) -> new ArrayList<>(1));
methodModels.add(methodDescriptor);
}
methods.forEach((methodName, methodList) -> {
Map<String, MethodDescriptor> descMap = descToMethods.computeIfAbsent(methodName, k -> new HashMap<>());
// not support BI_STREAM and SERVER_STREAM at the same time, for example,
// void foo(Request, StreamObserver<Response>) ---> SERVER_STREAM
// StreamObserver<Response> foo(StreamObserver<Request>) ---> BI_STREAM
long streamMethodCount = methodList.stream()
.peek(methodModel -> descMap.put(methodModel.getParamDesc(), methodModel))
.map(MethodDescriptor::getRpcType)
.filter(rpcType -> rpcType == MethodDescriptor.RpcType.SERVER_STREAM
|| rpcType == MethodDescriptor.RpcType.BI_STREAM)
.count();
if (streamMethodCount > 1L)
throw new IllegalStateException("Stream method could not be overloaded.There are " + streamMethodCount
+ " stream method signatures. method(" + methodName + ")");
});
}
public String getInterfaceName() {
return interfaceName;
}
public Class<?> getServiceInterfaceClass() {
return serviceInterfaceClass;
}
public Set<MethodDescriptor> getAllMethods() {
Set<MethodDescriptor> methodModels = new HashSet<>();
methods.forEach((k, v) -> methodModels.addAll(v));
return methodModels;
}
View on GitHub (pinned to 3a3043227f)
Solutions
- Rename one of the overloaded streaming methods so each streaming RPC has a unique name.
- If both signatures are genuinely needed, split them across two service interfaces rather than overloading.
- Confirm you did not accidentally duplicate a stream method (e.g. via interface inheritance merging two methods with the same name).
Example fix
// before (throws: two streaming methods named 'foo') void foo(StreamObserver<Resp> so); void foo(Req req, StreamObserver<Resp> so); // after (unique names) void foo(StreamObserver<Resp> so); void fooWithReq(Req req, StreamObserver<Resp> so);
Defensive patterns
Strategy: validation
Validate before calling
// Before export, ensure no two streaming methods share a name.
Map<String, Long> streamCounts = Arrays.stream(iface.getMethods())
.filter(m -> isStreamingShape(m))
.collect(Collectors.groupingBy(Method::getName, Collectors.counting()));
streamCounts.entrySet().stream()
.filter(e -> e.getValue() > 1)
.findFirst()
.ifPresent(e -> { throw new IllegalArgumentException("Duplicate stream method name: " + e.getKey()); }); Prevention
- Give every streaming RPC a unique method name; never overload streaming methods.
- Review service interfaces during code review for name collisions among stream methods.
- When generating interfaces from IDL, ensure the generator emits distinct names.
When it happens
Trigger: A service interface declares two or more methods with the same name that each classify as SERVER_STREAM or BI_STREAM (e.g. `void foo(StreamObserver<R>)` and `void foo(Req, StreamObserver<R>)`). The names collide; both are streaming; initMethods() throws during service descriptor construction.
Common situations: Adding a streaming overload to an existing streaming method while refactoring a Triple service. Auto-generating service interfaces from a schema that emits multiple streaming methods with identical names. Migrating from a unary API to streaming and forgetting to rename the old streaming method.
Related errors
- Bad stream method signature. method(${methodName}:${paramDes
- ${cls.getName()} generic type undefined!
- windowUpdateRatio must be > 0 and <= 1, but was: <windowUpda
- The interface class <interfaceClass> is not a interface!
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/1b9dea4f8f4284e0.
Report an issue: GitHub.