{"record":{"id":"4c7bbcaf2aafb7ec","repo":"apache/dubbo","slug":"can-not-merge-result-e-getmessage","errorCode":null,"errorMessage":"Can not merge result: {e.getMessage()}","messagePattern":"Can not 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":173,"sourceCode":"                        + returnType.getName() + \" ]\");\n            }\n            if (!Modifier.isPublic(method.getModifiers())) {\n                method.setAccessible(true);\n            }\n            result = resultList.remove(0).getValue();\n            try {\n                if (method.getReturnType() != void.class\n                        && method.getReturnType().isAssignableFrom(result.getClass())) {\n                    for (Result r : resultList) {\n                        result = method.invoke(result, r.getValue());\n                    }\n                } else {\n                    for (Result r : resultList) {\n                        method.invoke(result, r.getValue());\n                    }\n                }\n            } catch (Exception e) {\n                throw new RpcException(\"Can not merge result: \" + e.getMessage(), e);\n            }\n        } else {\n            Merger resultMerger;\n            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());","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java#L155-L191","documentation":"Thrown by MergeableClusterInvoker when the reflected merge method (merger=\".method\") is found but invoking it throws. Method.invoke can raise IllegalAccessException (access reduced after setAccessible restrictions), IllegalArgumentException (argument type mismatch), or InvocationTargetException (the merge method itself blew up). The original exception message is appended.","triggerScenarios":"merger=\".method\" resolves to a method whose visibility cannot be widened under the JVM's module/access rules; or the merge method receives a value whose runtime class is not assignable to its parameter (generic erasure mismatch); or the merge method body throws an exception when combining two real results.","commonSituations":"JDK 16+ strong encapsulation blocking setAccessible(true) on a non-public merge method in a library JAR; merge method declared with a wider/different parameter type than the actual return type; merge method throws NPE on null fields when one group returns empty data; record/immutable return types whose 'merge' mutates state unexpectedly.","solutions":["Make the merge method public so no setAccessible is required, avoiding IllegalAccessException under strict module encapsulation.","Ensure the merge method parameter type exactly matches the service return type (no raw/generic erasure mismatch).","Make the merge method null-safe: guard against null fields/values from any group before combining.","Add --add-opens on the relevant package if you cannot change the third-party return type, as a last resort."],"exampleFix":"// before: non-public merge + brittle null handling\nvoid merge(Stats other) { this.count += other.count; }\n\n// after: public, null-safe\npublic Stats merge(Stats other) {\n    if (other == null) return this;\n    this.count += other.count;\n    return this;\n}","handlingStrategy":"validation","validationCode":"// Confirm the merge method is public and null-safe before relying on it\nMethod m = ReturnType.class.getMethod(\"merge\", ReturnType.class);\nif (!Modifier.isPublic(m.getModifiers())) {\n    throw new IllegalStateException(\"merge method must be public\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return aggregator.call(req);\n} catch (RpcException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Can not merge result:\")) {\n        log.error(\"merge method threw; check access/null-safety\", e);\n    }\n    throw e;\n}","preventionTips":["Make merge methods public to avoid setAccessible failures under strict encapsulation.","Make merge methods null-safe across all fields.","Match the merge method parameter type exactly to the return type."],"tags":["cluster","mergeable","reflection","method-invocation","access"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}