AIP-193
Errors
Effective error communication is an important part of designing simple and intuitive APIs. Services returning standardized error responses enable API clients to construct centralized common error handling logic. This common logic simplifies API client applications and eliminates the need for cumbersome custom error handling code.
Guidance
Services must return a google.rpc.Status message when an
API error occurs, and must use the canonical error codes defined in
google.rpc.Code. More information about the particular codes
is available in the gRPC status code documentation.
Error messages should help a reasonably technical user understand and resolve the issue, and should not assume that the user is an expert in your particular API. Additionally, error messages must not assume that the user will know anything about its underlying implementation.
Error messages should be brief but actionable. Any extra information
should be provided in the details field. If even more information
is necessary, you should provide a link where a reader can get more
information or ask questions to help resolve the issue. It is also
important to set the right tone when writing messages.
The following sections describe the fields of google.rpc.Status.
Status.message
The message field is a developer-facing, human-readable "debug message"
which should be in English. (Localized messages are expressed using
a LocalizedMessage within the details field. See
LocalizedMessage for more details.) Any dynamic aspects of
the message must be included as metadata within the ErrorInfo that appears
in details.
The message is considered a problem description. It is intended for
developers to understand the problem and is more detailed than
ErrorInfo.reason, discussed later.
Messages should use simple descriptive language that is easy to understand (without technical jargon) to clearly state the problem that results in an error, and offer an actionable resolution to it.
For pre-existing (brownfield) APIs which have previously returned errors
without machine-readable identifiers, the value of message must
remain the same for any given error. For more information, see
Changing Error Messages.
Status.code
The code field is the status code, which must be the numeric value of
one of the elements of the google.rpc.Code enum.
For example, the value 5 is the numeric value of the NOT_FOUND
enum element.
Status.details
The details field allows messages with additional error information to
be included in the error response, each packed in a google.protobuf.Any
message.
Google defines a set of standard detail payloads for error details, which cover most common needs for API errors. Services should use these standard detail payloads when feasible.
Each type of detail payload must be included at most once. For
example, there must not be more than one BadRequest
message in the details, but there may be a BadRequest and a
PreconditionFailure.
All error responses must include an ErrorInfo within details. This
provides machine-readable identifiers so that users can write code against
specific aspects of the error.
The following sections describe the most common standard detail payloads.
ErrorInfo
The ErrorInfo message is the primary way to send a
machine-readable identifier. Contextual information should be
included in metadata in ErrorInfo and must be included if it
appears within an error message.
The reason field is a short snake_case description of the cause of the
error. Error reasons are unique within a particular domain of errors.
The reason must be at most 63 characters and match a regular expression of
[A-Z][A-Z0-9_]+[A-Z0-9]. (This is UPPER_SNAKE_CASE, without leading
or trailing underscores, and without leading digits.)
The reason should be terse, but meaningful enough for a human reader to understand what the reason refers to.
Good examples:
CPU_AVAILABILITYNO_STOCKCHECKED_OUTAVAILABILITY_ERROR
Bad examples:
THE_BOOK_YOU_WANT_IS_NOT_AVAILABLE(overly verbose)ERROR(too general)
The domain field is the logical grouping to which the reason belongs.
The domain must be a globally unique value, and is typically the name of the service
that generated the error, e.g. pubsub.googleapis.com.
The (reason, domain) pair form a machine-readable way of identifying a particular error. Services must use the same (reason, domain) pair for the same error, and must not use the same (reason, domain) pair for logically different errors. The decision about whether two errors are "the same" or not is not always clear, but should generally be considered in terms of the expected action a client might take to resolve them.
The metadata field is a map of key/value pairs providing additional
dynamic information as context. Each key within metadata must be at most
64 characters long, and conform to the regular expression [a-z][a-zA-Z0-9-_]+.
Any request-specific information which contributes to the Status.message or
LocalizedMessage.message messages must be represented within metadata.
This practice is critical so that machine actors do not need to parse error
messages to extract information.
For example consider the following message:
An <e2-medium> VM instance with <local-ssd=3,nvidia-t4=2> is currently unavailable in the <us-east1-a> zone. Consider trying your request in the <us-central1-f,us-central1-c> zone(s), which currently has/have capacity to accommodate your request. Alternatively, you can try your request again with a different VM hardware configuration or at a later time. For more information, see the troubleshooting documentation.
The ErrorInfo.metadata map for the same error could be:
"zone": "us-east1-a""vmType": "e2-medium""attachment": "local-ssd=3,nvidia-t4=2""zonesWithCapacity": "us-central1-f,us-central1-c"
Additional contextual information that does not appear in an error message
may also be included in metadata to allow programmatic use by the client.
The metadata included for any given (reason,domain) pair can evolve over time:
- New keys may be included
- All keys that have been included must continue to be included (but may have empty values)
In other words, once a user has observed a given key for a (reason, domain) pair, the service must allow them to rely on it continuing to be present in the future.
The set of keys provided in each (reason, domain) pair is independent from other pairs,
but services should aim for consistent key naming. For example, two error reasons
within the same domain should not use metadata keys of vmType and virtualMachineType.
LocalizedMessage
google.rpc.LocalizedMessage is used to provide an error
message which should be localized to a user-specified locale where
possible.
If the Status.message field has a sub-optimal value
which cannot be changed due to the constraints in the
Changing Error Messages section, LocalizedMessage
may be used to provide a better error message even when no user-specified
locale is available.
Regardless of how the locale for the message was determined, both the locale
and message fields must be populated.
The locale field specifies the locale of the message,
following IETF bcp47 (Tags for
Identifying Languages). Example values: "en-US", "fr-CH", "es-MX".
The message field contains the localized text itself. This
should include a brief description of the error and a call to action
to resolve the error. The message should include contextual information
to make the message as specific as possible. Any contextual information
in the message must be included in ErrorInfo.metadata. See
ErrorInfo for more details of how contextual information
may be included in a message and the corresponding metadata.
The LocalizedMessage payload should contain the complete resolution
to the error. If more information is needed than can reasonably fit in this
payload, then additional resolution information must be provided in
a Help payload. See the Help section for guidance.
Help
When other textual error messages (in Status.message or
LocalizedMessage.message) don't provide the user sufficient
context or actionable next steps, or if there are multiple points of
failure that need to be considered in troubleshooting, a link to
supplemental troubleshooting documentation must be provided in the
Help payload.
Provide this information in addition to a clear problem definition and
actionable resolution, not as an alternative to them. The linked
documentation must clearly relate to the error. If a single page
contains information about multiple errors, the
ErrorInfo.reason value must be used to narrow down
the relevant information.
The description field is a textual description of the linked information.
This must be suitable to display to a user as text for a hyperlink.
This must be plain text (not HTML, Markdown etc).
Example description value: "Troubleshooting documentation for STOCKOUT errors"
The url field is the URL to link to. This must be an absolute URL,
including scheme.
Example url value:
"https://cloud.google.com/compute/docs/resource-error"
For publicly-documented services, even those with access controls on actual usage, the linked content must be accessible without authentication.
For privately-documented services, the linked content may require authentication.
Error messages
Textual error messages can be present in both Status.message and
LocalizedMessage.message fields. Messages should be succinct but
actionable, with request-specific information (such as a resource name
or region) providing precise details where appropriate. Any request-specific
details must be present in ErrorInfo.metadata.
Changing error messages
Changing the content of Status.message over time must be done carefully,
to avoid breaking clients who have previously had to rely on the message
for all information. See the rationale section
for more details.
For a given RPC:
- If the RPC has always returned
ErrorInfowith machine-readable information, the content ofStatus.messagemay change over time. (For example, the API producer may provide a clearer explanation, or more request-specific information.) - Otherwise, the content of
Status.messagemust be stable, providing the same text with the same request-specific information. Instead of changingStatus.message, the API should include a
View on GitHub