{"record":{"id":"c293e1cf1b4f1900","repo":"apache/dubbo","slug":"there-is-no-merger-to-merge-result","errorCode":null,"errorMessage":"There is no merger to merge result.","messagePattern":"There is no merger to merge result\\.","errorType":"exception","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java","lineNumber":195,"sourceCode":"            ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(\n                    invocation.getModuleModel().getApplicationModel());\n\n            if (ConfigUtils.isDefault(merger)) {\n                resultMerger = applicationModel\n                        .getBeanFactory()\n                        .getBean(MergerFactory.class)\n                        .getMerger(returnType);\n            } else {\n                resultMerger = applicationModel.getExtensionLoader(Merger.class).getExtension(merger);\n            }\n            if (resultMerger != null) {\n                List<Object> rets = new ArrayList<>(resultList.size());\n                for (Result r : resultList) {\n                    rets.add(r.getValue());\n                }\n                result = resultMerger.merge(rets.toArray((Object[]) Array.newInstance(returnType, 0)));\n            } else {\n                throw new RpcException(\"There is no merger to merge result.\");\n            }\n        }\n        return AsyncRpcResult.newDefaultAsyncResult(result, invocation);\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return directory.getInterface();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return directory.isAvailable();\n    }\n\n    @Override\n    public void destroy() {\n        directory.destroy();","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java#L177-L213","documentation":"Thrown by MergeableClusterInvoker when merger resolution finds no Merger to use. When merger is neither a leading-dot method nor resolves to a default ('true'/'default') via MergerFactory nor to a named Merger SPI extension, resultMerger stays null and Dubbo cannot combine the per-group results.","triggerScenarios":"Configuring merger=\"someName\" where 'someName' is not 'true'/'default' and is not a registered Merger @SPI extension; or merger=\"true\"/\"default\" but MergerFactory has no built-in Merger registered for the service return type (e.g. a custom DTO with no array-merger).","commonSituations":"Using merger=\"true\" on a return type that has no corresponding MergerFactory entry (custom objects rather than primitives/collections/arrays); typo in a custom Merger extension name; custom Merger @SPI class not placed under META-INF/dubbo or misspelled name; upgrading Dubbo and dropping the SPI file.","solutions":["Implement and register a custom org.apache.dubbo.rpc.cluster.Merger @SPI for your return type under META-INF/dubbo and reference it by name (merger=\"myMerger\").","If the return type is a primitive/array/collection, ensure you use merger=\"true\" so MergerFactory can pick the built-in merger; verify the type is supported.","Correct any typo in the merger name and confirm the SPI file name matches the extension loader path.","Alternatively use the dot-method form (merger=\".combine\") if the return type can merge itself."],"exampleFix":"// before: no merger registered for custom DTO\n<dubbo:reference interface=\"com.acme.Fanout\" group=\"*\" merger=\"true\"/>\n\n// after: register a named SPI merger\npublic class ReportMerger implements Merger<Report> {\n    @Override public Report merge(Report[] others) { /* ... */ }\n}\n// META-INF/dubbo/org.apache.dubbo.rpc.cluster.Merger  ->  report=com.acme.ReportMerger\n<dubbo:reference interface=\"com.acme.Fanout\" group=\"*\" merger=\"report\"/>","handlingStrategy":"validation","validationCode":"// At startup, verify a Merger resolves for the return type / name\nMerger<?> m = ConfigUtils.isDefault(mergerName)\n    ? mergerFactory.getMerger(returnType)\n    : extensionLoader.getExtension(mergerName);\nif (m == null) {\n    throw new IllegalStateException(\"no merger resolves for \" + mergerName + \" / \" + returnType);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register custom Merger @SPI classes under META-INF/dubbo with the exact extension name.","Use merger=\"true\" only for return types MergerFactory supports (primitives, arrays, collections).","Add a startup smoke test that resolves the configured merger name."],"tags":["cluster","mergeable","merger","spi","config"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}