Standard error responses
If a Reporting API request is successful, the API returns a 200
.
If an error occurs with a request, the API returns an HTTP
status code, status, and reason in the response based on the type of error.
Additionally, the body of the response contains a detailed description
of what caused the error. Here's an example of an error response:
{
"error": {
"code": 403,
"message": "User does not have sufficient permissions for this profile.",
"status": "PERMISSION_DENIED"
}
}
Error table
Code | Status | Description | Recommended Action |
---|---|---|---|
400 | INVALID_ARGUMENT |
The request is invalid; a required argument may be missing, exceeds limits, or has an invalid value. | Review the error message for details. This error will fail again if the client retries it. |
401 | UNAUTHENTICATED |
The client is not authenticated properly. | Do not retry without fixing the problem. You need to get a new auth token. |
403 | PERMISSION_DENIED |
Indicates the request for data to which the user does not have access. | Do not retry without fixing the problem. You need to get sufficient permissions to perform the operation on the specified entity. |
429 | RESOURCE_EXHAUSTED AnalyticsDefaultGroupCLIENT_PROJECT-1d |
Indicates that the requests per day per project quota has been exhausted. | Do not retry without fixing the problem. You have used up your daily quota. |
429 | RESOURCE_EXHAUSTED AnalyticsDefaultGroupCLIENT_PROJECT-100s |
Indicates that the requests per 100 seconds per project quota has been exhausted. | Retry using exponential back-off. You need to slow down the rate at which you are sending the requests. |
429 | RESOURCE_EXHAUSTED AnalyticsDefaultGroupUSER-100s |
Indicates that the requests per 100 seconds per user per project quota has been exhausted. | Retry using exponential back-off. You need to slow down the rate at which you are sending the requests. |
429 | RESOURCE_EXHAUSTED DiscoveryGroupCLIENT_PROJECT-100s |
Indicates that the discovery requests per 100 seconds quota has been exhausted. | The discovery response does not change frequently; cache the discovery response locally or retry using exponential back-off. You need to slow down the rate at which you are sending the requests. |
500 | INTERNAL |
Unexpected internal server error occurred. | Do not retry this query more than once. |
503 | BACKEND_ERROR |
Server returned an error. | Do not retry this query more than once. |
503 | UNAVAILABLE |
The service was unable to process the request. | This is most likely a transient condition and may be corrected by retrying with exponential back-off. |
Implementing Exponential Backoff
Exponential backoff is the process of a client periodically retrying a failed request over an increasing amount of time. It is a standard error handling strategy for network applications. The Reporting API is designed with the expectation that clients which choose to retry failed requests do so using exponential backoff. Besides being "required", using exponential backoff increases the efficiency of bandwidth usage, reduces the number of requests required to get a successful response, and maximizes the throughput of requests in concurrent environments.
The flow for implementing simple exponential backoff is as follows.
- Make a request to the API
- Receive an error response that has a retry-able error code
- Wait 1s +
random_number_milliseconds
seconds - Retry request
- Receive an error response that has a retry-able error code
- Wait 2s +
random_number_milliseconds
seconds - Retry request
- Receive an error response that has a retry-able error code
- Wait 4s +
random_number_milliseconds
seconds - Retry request
- Receive an error response that has a retry-able error code
- Wait 8s +
random_number_milliseconds
seconds - Retry request
- Receive an error response that has a retry-able error code
- Wait 16s +
random_number_milliseconds
seconds - Retry request
- If you still get an error, stop and log the error.
In the above flow, random_number_milliseconds
is a random
number of milliseconds less than or equal to 1000. This is necessary
to avoid certain lock errors in some concurrent implementations.
random_number_milliseconds
must be redefined after each wait.
Note: the wait is always
(2 ^ n) + random_number_milliseconds
, where
n is a monotonically increasing integer initially defined
as 0. n is incremented by 1 for each iteration (each request).
The algorithm is set to terminate when n is 5. This ceiling is in place only to stop clients from retrying infinitely, and results in a total delay of around 32 seconds before a request is deemed "an unrecoverable error".
The following Python code is an implementation of the above
flow for recovering from errors that occur in a method called
makeRequest
.
import random import time from apiclient.errors import HttpError def makeRequestWithExponentialBackoff(analytics): """Wrapper to request Google Analytics data with exponential backoff. The makeRequest method accepts the analytics service object, makes API requests and returns the response. If any error occurs, the makeRequest method is retried using exponential backoff. Args: analytics: The analytics service object Returns: The API response from the makeRequest method. """ for n in range(0, 5): try: return makeRequest(analytics) except HttpError, error: if error.resp.reason in ['userRateLimitExceeded', 'quotaExceeded', 'internalServerError', 'backendError']: time.sleep((2 ** n) + random.random()) else: break print "There has been an error, the request never succeeded."