Skip to main content
Every refusal carries an ErrorDetail in the status details, and it says what POST /secure/send would have answered for the same request. So everything written about REST errors applies here too — the gRPC code is the transport’s way of saying it, and ErrorDetail is the detail.

Reading ErrorDetail

It travels in the standard rich-status trailer (grpc-status-details-bin). Read it with your library’s helper: On a SendStream the same ErrorDetail arrives inline in the result’s error field, beside the numeric code. Branch on code, not on message. The message is for a person reading a log and may be worded differently in a later release; the codes are part of the frozen contract. When a retry helps, a standard google.rpc.RetryInfo is packed beside ErrorDetail with the same delay, for client libraries that honour it.

Sending

Nothing refused is charged, and nothing refused counts against your rate limit.
RESOURCE_EXHAUSTED means two different things here. With an ErrorDetail whose code is RATE_LIMITED, slow down. With no ErrorDetail at all, the request was too large and will never succeed as it is.

OUTCOME_UNKNOWN: retry only with client_ref

OUTCOME_UNKNOWN is UNKNOWN, not UNAVAILABLE, on purpose. The message may be on its way and has been charged. Many gRPC client libraries retry UNAVAILABLE automatically — which here would send it twice.Retry an UNKNOWN only with the same client_ref. If the first attempt went through, you get its message_id back with duplicate: true and nothing is sent again. If it did not, the retry sends it. Without a client_ref there is no safe retry: the message_id in the detail is the one to watch for on a receipt.
For the same reason, if you configure a retry policy in your client library (a gRPC service config retryPolicy), list UNAVAILABLE and RESOURCE_EXHAUSTED in it and never UNKNOWN.

Sessions and the API itself

UNAUTHENTICATED covers three different situations, so read ErrorDetail.code: only SESSION_EXPIRED is cured by logging in again. See Authentication and sessions.

Receipts

An Ack naming a receipt that is already gone is not an error — it is counted in already_gone. See Delivery receipts over gRPC.

REST API errors

The same refusals, as HTTP statuses.

Handling errors

Building for the receipt rather than the response.