{"record":{"id":"1b9dea4f8f4284e0","repo":"apache/dubbo","slug":"stream-method-could-not-be-overloaded-there-are","errorCode":null,"errorMessage":"Stream method could not be overloaded.There are ${streamMethodCount} stream method signatures. method(${methodName})","messagePattern":"Stream method could not be overloaded\\.There are (.+?) stream method signatures\\. method\\((.+?)\\)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ReflectionServiceDescriptor.java","lineNumber":90,"sourceCode":"            MethodDescriptor methodDescriptor = new ReflectionMethodDescriptor(method);\n\n            List<MethodDescriptor> methodModels = methods.computeIfAbsent(method.getName(), (k) -> new ArrayList<>(1));\n            methodModels.add(methodDescriptor);\n        }\n\n        methods.forEach((methodName, methodList) -> {\n            Map<String, MethodDescriptor> descMap = descToMethods.computeIfAbsent(methodName, k -> new HashMap<>());\n            // not support BI_STREAM and SERVER_STREAM at the same time, for example,\n            // void foo(Request, StreamObserver<Response>)  ---> SERVER_STREAM\n            // StreamObserver<Response> foo(StreamObserver<Request>)   ---> BI_STREAM\n            long streamMethodCount = methodList.stream()\n                    .peek(methodModel -> descMap.put(methodModel.getParamDesc(), methodModel))\n                    .map(MethodDescriptor::getRpcType)\n                    .filter(rpcType -> rpcType == MethodDescriptor.RpcType.SERVER_STREAM\n                            || rpcType == MethodDescriptor.RpcType.BI_STREAM)\n                    .count();\n            if (streamMethodCount > 1L)\n                throw new IllegalStateException(\"Stream method could not be overloaded.There are \" + streamMethodCount\n                        + \" stream method signatures. method(\" + methodName + \")\");\n        });\n    }\n\n    public String getInterfaceName() {\n        return interfaceName;\n    }\n\n    public Class<?> getServiceInterfaceClass() {\n        return serviceInterfaceClass;\n    }\n\n    public Set<MethodDescriptor> getAllMethods() {\n        Set<MethodDescriptor> methodModels = new HashSet<>();\n        methods.forEach((k, v) -> methodModels.addAll(v));\n        return methodModels;\n    }\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ReflectionServiceDescriptor.java#L72-L108","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before (throws: two streaming methods named 'foo')\nvoid foo(StreamObserver<Resp> so);\nvoid foo(Req req, StreamObserver<Resp> so);\n\n// after (unique names)\nvoid foo(StreamObserver<Resp> so);\nvoid fooWithReq(Req req, StreamObserver<Resp> so);","handlingStrategy":"validation","validationCode":"// Before export, ensure no two streaming methods share a name.\nMap<String, Long> streamCounts = Arrays.stream(iface.getMethods())\n    .filter(m -> isStreamingShape(m))\n    .collect(Collectors.groupingBy(Method::getName, Collectors.counting()));\nstreamCounts.entrySet().stream()\n    .filter(e -> e.getValue() > 1)\n    .findFirst()\n    .ifPresent(e -> { throw new IllegalArgumentException(\"Duplicate stream method name: \" + e.getKey()); });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["streaming","triple","method-overloading","service-interface"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}