apache/dubbo · error · RpcException
Failed to invoke service {entry.getKey()}: {e.getMessage()}
Error message
Failed to invoke service {entry.getKey()}: {e.getMessage()} What it means
Thrown by MergeableClusterInvoker when fetching the async result of one group's invocation throws any non-RpcException (the get(Integer.MAX_VALUE, ...) on a per-group future fails). MergeableCluster fans a call out across all configured groups and aggregates; if one group's async future fails to resolve, the whole merge is aborted with this wrapping RpcException naming the failing group's service key.
Source
Thrown at dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java:134
List<Result> resultList = new ArrayList<>(results.size());
for (Map.Entry<String, Result> entry : results.entrySet()) {
Result asyncResult = entry.getValue();
try {
Result r = asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
if (r.hasException()) {
log.error(
LoggerCodeConstants.CLUSTER_FAILED_GROUP_MERGE,
"Invoke " + getGroupDescFromServiceKey(entry.getKey()) + " failed: "
+ r.getException().getMessage(),
"",
r.getException().getMessage());
} else {
resultList.add(r);
}
} catch (Exception e) {
throw new RpcException("Failed to invoke service " + entry.getKey() + ": " + e.getMessage(), e);
}
}
if (resultList.isEmpty()) {
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else if (resultList.size() == 1) {
return AsyncRpcResult.newDefaultAsyncResult(resultList.get(0).getValue(), invocation);
}
if (returnType == void.class) {
return AsyncRpcResult.newDefaultAsyncResult(invocation);
}
if (merger.startsWith(".")) {
merger = merger.substring(1);
Method method;
try {
method = returnType.getMethod(merger, returnType);View on GitHub (pinned to 3a3043227f)
Solutions
- Identify the failing group from the embedded service key and verify that group's providers are registered, healthy, and reachable.
- Align timeouts: ensure the consumer timeout covers the slowest group so no single group future times out during the merge wait.
- Confirm every group exposes the same method signature and serialization is compatible across groups (same interface version).
- If partial results are acceptable, consider a custom Cluster/Merger that tolerates a subset of group failures instead of the built-in mergeable cluster.
Example fix
// before: one slow/failed group aborts the entire aggregated call <dubbo:reference interface="com.acme.Aggregator" group="*" merger="true"/> // after: ensure all groups share timeout + are healthy; isolate the weak group <dubbo:reference interface="com.acme.Aggregator" group="a,b" merger="true" timeout="3000"/>
Defensive patterns
Strategy: try-catch
Validate before calling
// Before aggregating, confirm each group has available providers
List<Invoker<T>> live = invokers.stream().filter(Invoker::isAvailable).collect(toList());
if (live.size() < requiredGroupCount) {
log.warn("not all groups available before merge: {}", live);
} Try / catch
try {
return aggregator.call(req);
} catch (RpcException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Failed to invoke service ")) {
String failingGroup = extractGroup(e); // from message
alertPartialGroupFailure(failingGroup, e);
}
throw e;
} Prevention
- Align consumer timeout with the slowest group so no group future fails the merge.
- Keep method signatures and serialization identical across all groups.
- Monitor each group independently so a degrading group is caught before it breaks aggregation.
When it happens
Trigger: Invoking a method configured with group aggregation (multiple groups, merger= set) where one group's invocation future completes exceptionally with a non-RpcException cause, e.g. a TimeoutException, ExecutionException, or a serialization/decoding error during asyncResult.get(). The failing group's service key is embedded in the message.
Common situations: One provider group is unhealthy/down while others are up (partial outage under merge); per-group timeout misconfiguration causing one future to fail; version skew where one group returns an incompatible type that fails deserialization; registry split-brain leaving one group with stale invokers.
Related errors
- Arguments' types are different
- Can not merge result because missing method [ {merger} ] in
- Can not merge result: {e.getMessage()}
- There is no merger to merge result.
- INTERNAL_ERROR
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/37270ea61fe35846.
Report an issue: GitHub.