Skip to content

doc: Document error handling and Observer callback behavior - #11876

Open
kannanjgithub wants to merge 5 commits into
grpc:masterfrom
kannanjgithub:inconsistencies-error-handling
Open

doc: Document error handling and Observer callback behavior#11876
kannanjgithub wants to merge 5 commits into
grpc:masterfrom
kannanjgithub:inconsistencies-error-handling

Conversation

@kannanjgithub

@kannanjgithub kannanjgithub commented Feb 4, 2025

Copy link
Copy Markdown
Contributor

Fixes #7558.

@kannanjgithub
kannanjgithub requested a review from ejona86 February 4, 2025 08:40
@kannanjgithub

Copy link
Copy Markdown
Contributor Author

I have deliberately only documented the async versions of the calls, not the blocking and futures versions, for now. Will copy the contents over when approved for the async version.

* Creates a {@link ServerCallHandler} for a unary call method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
* <p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't have paragraphs after @param. You shouldn't use </p> (javadoc uses HTML style, not XHTML). Having an h3 in a p doesn't make sense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* trailer with END_STREAM is sent, the server side call is considered to be closed.
* </p>
*/
public static <ReqT, RespT> ServerCallHandler<ReqT, RespT> asyncUnaryCall(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adapter doesn't look much like the server stub API. This documentation seems like it'd be better on UnaryMethod, as then you could say "responseObserver" and talk about that specific instance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* <h3>Server errors</h3>
* If the throwable sent to the server's outbound {@link StreamObserver}'s onError
* is a {@link StatusException} or {@link StatusRuntimeException}, that status code will be sent
* and UNKNOWN status code otherwise. Its description will be encoded to the stream trailer, but

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"stream trailer" is weird and not going to mean much to users. And END_STREAM is pulling in transport details that we shouldn't have in our API (our API does not generally assume the HTTP/2 transport).

Consider something closer to this:

Calling {@code responseObserver}'s {@link StreamObserver#onCompleted} or {@link
StreamObserver#onError} is the end of the RPC. {@code onCompleted()} will close the RPC with
status code OK. {@code onError()} will convert the Throwable to a Status with {@link
Status#fromThrowable} and trailers with {@link Status#trailersFromThrowable}. The
{@link Status#getCause} is not sent to the client, except if done by an interceptor.
Callers generally create a Throwable with {@link Status#asException()},
{@link Status#asException(Metadata)}, {@link Status#asRuntimeException()}, or
{@link Status#asRuntimeException(Metadata)}.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* <h3>Client errors</h3>
* The server's request stream observer will receive an
* onError callback with a {@link io.grpc.StatusRuntimeException} for the cancellation with the
* message 'Client cancelled', and exception cause set to null because the actual exception

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we don't want to specify what message will be used. The important part is the status is CANCELLED. And in general, it is probably best for users to use Status.fromThrowable() to get the Status, as then they can just assume it is a Status as opposed to instanceof checks, casts, and some fall-back behavior if it isn't the expected type. On server-side that really doesn't matter because the error never has much information, but matters more on client-side. So it may be more "the Throwable, when converted to a status with Status.fromThrowable(), always has the status code CANCELLED."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* {@code beforeStart()} will be called.
*
* <h3>Server errors</h3>
* If the throwable sent to the server's outbound {@link StreamObserver}'s onError

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like it should only be on server-side. Let's talk more about the client's perspective.

If the server completes the RPC with status code OK, then {@code responseObserver.onCompleted()}
is called at the end of the RPC. Otherwise the status and trailers are passed as a Throwable to
{@code onError()} and can be accessed with {@link Status#fromThrowable} and {@link
Status#trailersFromThrowable}.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@kannanjgithub
kannanjgithub force-pushed the inconsistencies-error-handling branch 2 times, most recently from 3ebcb7b to 813a53b Compare August 27, 2026 12:42
@kannanjgithub
kannanjgithub force-pushed the inconsistencies-error-handling branch from 813a53b to f8b457a Compare August 27, 2026 12:47
# Conflicts:
#	stub/src/main/java/io/grpc/stub/ClientCalls.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistencies in Bidirectional Streaming Error Handling

2 participants