Cloud Native 12 min read

How Dubbo 3.0 Enables Custom Exceptions with the Triple Protocol

This article explains how Dubbo 3.0’s Triple RPC protocol now supports custom exception serialization, detailing the original exception handling flow, the limitations of header‑based error transport, and the proposed TripleWrapper‑Protobuf solution for reliable client‑side error capture.

Alibaba Cloud Native
Alibaba Cloud Native
Alibaba Cloud Native
How Dubbo 3.0 Enables Custom Exceptions with the Triple Protocol

Background

In many business scenarios developers need to throw custom exceptions that carry specific error information. Traditionally this is done by re‑throwing the exception in a catch block or by using an ExceptionBuilder to return an exception object to the consumer.

public void deal() {
    try {
        // doSomething
        ...
    } catch (IGreeterException e) {
        // additional handling
        throw e;
    }
}
provider.send(new ExceptionBuilders.IGreeterExceptionBuilder()
    .setDescription('异常描述信息'));

On the consumer side the exception can be caught with instanceof checks:

try {
    greeterProxy.echo(REQUEST_MSG);
} catch (IGreeterException e) {
    // handle specific error
    ...
}

Dubbo 3.0 and the Triple Protocol

Dubbo 3.0 embraces cloud‑native principles and introduces the Triple protocol, which is built on HTTP/2, compatible with gRPC, and supports various streaming models. Triple also adds IDL‑based service definitions.

When Triple is used, the provider can generate custom exception information and the protocol guarantees that the client receives the exception message. However, Dubbo wraps all provider‑side exceptions into a generic RpcException inside AbstractInvoker.waitForResultIfSync, losing the original exception type and message:

try {
    greeterProxy.echo(REQUEST_MSG);
} catch (RpcException e) {
    e.printStackTrace();
}

Because ExceptionBuilder is not widely adopted, Dubbo now adds explicit support for custom exceptions while still deprecating the builder approach.

Consumer‑Side Exception Flow

The consumer obtains a proxy bean from the Spring container. Calls are delegated to ProxyFactory (default JavassistProxyFactory), which creates an anonymous subclass of AbstractProxyInvoker. The overridden doInvoke forwards the request to a generated Wrapper class, which ultimately invokes InvocationUtilAbstractInvoker → concrete invoker. The provider’s response is wrapped in an AppResponse. If the response contains an exception, AppResponse.recreate() throws it, allowing the consumer to catch the specific exception.

public Object recreate() throws Throwable {
    if (exception != null) {
        try {
            Object stackTrace = exception.getStackTrace();
            if (stackTrace == null) {
                exception.setStackTrace(new StackTraceElement[0]);
            }
        } catch (Exception e) {
            // ignore
        }
        throw exception;
    }
    return result;
}
Dubbo consumer exception handling flow diagram
Dubbo consumer exception handling flow diagram

Provider‑Side ExceptionFilter

On the provider side, org.apache.dubbo.rpc.filter.ExceptionFilter is part of the filter chain and packages any thrown exception into an AppResponse. The following diagram (omitted here) shows the filter’s position.

ExceptionFilter processing flow
ExceptionFilter processing flow

Serialization Choices and Header‑Size Limitation

To transmit custom exception objects, they must be serialized. Common options include Hessian2 (Dubbo/HSF default), JSON, and protobuf (gRPC native). Triple adopts protobuf by default. Because protobuf cannot directly serialize an exception object, a wrapper (e.g., TripleExceptionWrapperUtils) is used to serialize the exception into the trailer.

However, HTTP/2 limits header size (typically 8 KB). Large serialized exceptions may exceed this limit, causing transmission failures and consuming valuable header space.

Proposed Solution: TripleWrapper + Protobuf in Body

The community discussed moving the serialized exception from the trailer to the message body, using a TripleWrapper combined with protobuf. This avoids header‑size constraints while preserving exception details. The revised flow serializes the exception into the body and returns a 200 status code, treating the payload as a business‑level error rather than a transport error.

TripleWrapper + Protobuf serialization diagram
TripleWrapper + Protobuf serialization diagram

Provider Invocation Logic with TripleWrapper

public void invoke() {
    // ...
    try {
        // invoke service method
        final Result response = invoker.invoke(invocation);
        // async wait for result
        response.whenCompleteWithContext((r, t) -> {
            if (t != null) {
                // method threw an exception
                responseObserver.onError(t);
                return;
            }
            if (response.hasException()) {
                // business exception handling
                onReturn(response.getException());
                return;
            }
            // normal result
            onReturn(r.getValue());
        });
    }
    // ...
}

The revised version only adds the serialized exception to the body when it is non‑null, then the consumer deserializes it using the same protobuf definition.

Final exception flow with TripleWrapper
Final exception flow with TripleWrapper

Conclusion

Adding custom exception support to Dubbo 3.0 required careful consideration of protocol compatibility, header size limits, and serialization strategy. By moving exception payloads to the body with a protobuf‑based wrapper, Dubbo preserves rich error information while staying aligned with cloud‑native and gRPC design principles.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

cloud nativeCustom ExceptionJava RPCtriple-protocol
Alibaba Cloud Native
Written by

Alibaba Cloud Native

We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.