This guide explains how the Data Manager API handles and communicates errors. Understanding the structure and meaning of API errors is crucial for building robust applications that can gracefully handle issues, from invalid input to temporary service unavailability.
The Data Manager API follows the standard Google API error model, which is based
on gRPC Status codes
. Each API response that results in an
error includes a Status
object with:
- A numeric error code.
- An error message.
- Optional, additional error details.
Canonical error codes
The Data Manager API uses a set of canonical error codes defined by gRPC and HTTP. These codes provide a high-level indication of the error type. You should always check this code first to understand the fundamental nature of the problem.
For more details on these codes, see API Design Guide - Error codes .
Handle errors
Follow these steps when a request fails:
-
Check the error code to find the type of error.
- If you use gRPC, the error code is in the
codefield of theStatus. If you use a client library , it may throw a specific type of exception that corresponds to the error code. For example, the client library for Java throws acom.google.api.gax.rpc.InvalidArgumentExceptionif the error code isINVALID_ARGUMENT. - If you use REST, the error code is in the error response at
error.status, and the corresponding HTTP status is aterror.code.
- If you use gRPC, the error code is in the
-
Check for the standard detail payload for the error code. The standard detail payloads are a set of messages for errors from Google APIs . They give you error details in a structured and consistent way. Each error from the Data Manager API may have multiple standard detail payload messages. The Data Manager API client libraries have helper methods to get the standard detail payloads from an error.
No matter the error code, we recommend you check for and log the
ErrorInfo,RequestInfo,Help, andLocalizedMessagepayloads.-
ErrorInfohas information that might not be in other payloads. -
RequestInfohas the request ID, which is helpful if you need to contact support . -
HelpandLocalizedMessagecontain links and other details to help you address the error.
In addition, the
BadRequestpayload is useful forINVALID_ARGUMENTerrors since it provides information about which fields caused the error. -
Standard detail payloads
The most common standard detail payloads for the Data Manager API are:
BadRequest
Check for the BadRequest
payload when a request fails with INVALID_ARGUMENT
(HTTP status code 400
).
A BadRequest
message shows that the request had fields with bad values, or was
missing a value for a required field. Check the field_violations
list in the BadRequest
to find which fields have errors. Each field_violations
entry
has information to help you fix the error:
-
field -
The location of the field in the request, using a camel case path syntax.
If a path points to an item in a list (a
repeatedfield), its index is shown in square brackets ([...]) after the list's name.For example,
destinations[0].operating_account.account_idis theaccount_idin theoperating_accountof the first item in thedestinationslist. -
description -
An explanation of why the value caused an error.
-
reason -
The
ErrorReasonenum, such asINVALID_HEX_ENCODINGorINVALID_CURRENCY_CODE.
Examples of BadRequest
Here's a sample response for an INVALID_ARGUMENT
error with a BadRequest
message. The field_violations
show the error is an accountId
that is not a
number. The field
value destinations[0].login_account.account_id
shows the accountId
with a field violation is in the login_account
of the first item
in the destinations
list.
{
"error"
:
{
"code"
:
400
,
"message"
:
"There was a problem with the request."
,
"status"
:
"INVALID_ARGUMENT"
,
"details"
:
[
{
"@type"
:
"type.googleapis.com/google.rpc.ErrorInfo"
,
"reason"
:
"INVALID_ARGUMENT"
,
"domain"
:
"datamanager.googleapis.com"
,
"metadata"
:
{
"requestId"
:
"t-a8896317-069f-4198-afed-182a3872a660"
}
},
{
"@type"
:
"type.googleapis.com/google.rpc.RequestInfo"
,
"requestId"
:
"t-a8896317-069f-4198-afed-182a3872a660"
},
{
"@type"
:
"type.googleapis.com/google.rpc.BadRequest"
,
"fieldViolations"
:
[
{
"field"
:
"destinations[0].login_account.account_id"
,
"description"
:
"String is not a valid number."
,
"reason"
:
"INVALID_NUMBER_FORMAT"
}
]
}
]
}
}
Here's another sample response from an INVALID_ARGUMENT
error with a BadRequest
message. In this case, the field_violations
list shows two
errors:
-
The first
eventhas a value that's not hex-encoded on the event's second user identifier . -
The second
eventhas a value that's not hex-encoded on the event's third user identifier .
{
"error"
:
{
"code"
:
400
,
"message"
:
"There was a problem with the request."
,
"status"
:
"INVALID_ARGUMENT"
,
"details"
:
[
{
"@type"
:
"type.googleapis.com/google.rpc.ErrorInfo"
,
"reason"
:
"INVALID_ARGUMENT"
,
"domain"
:
"datamanager.googleapis.com"
,
"metadata"
:
{
"requestId"
:
"t-6bc8fb83-d648-4942-9c49-2604276638d8"
}
},
{
"@type"
:
"type.googleapis.com/google.rpc.RequestInfo"
,
"requestId"
:
"t-6bc8fb83-d648-4942-9c49-2604276638d8"
},
{
"@type"
:
"type.googleapis.com/google.rpc.BadRequest"
,
"fieldViolations"
:
[
{
"field"
:
"events.events[0].user_data.user_identifiers[1]"
,
"description"
:
"The HEX encoded value is malformed."
,
"reason"
:
"INVALID_HEX_ENCODING"
},
{
"field"
:
"events.events[1].user_data.user_identifiers[2]"
,
"description"
:
"The HEX encoded value is malformed."
,
"reason"
:
"INVALID_HEX_ENCODING"
}
]
}
]
}
}
RequestInfo
Check for the RequestInfo
payload whenever a request fails. A RequestInfo
contains the request_id
that uniquely identifies your API request.
{
"@type"
:
"type.googleapis.com/google.rpc.RequestInfo"
,
"requestId"
:
"t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}
When logging errors or contacting support , make sure to include the request ID to help with diagnosing issues.
ErrorInfo
Check for the ErrorInfo
message to retrieve additional information that
may not be captured in the other standard detail payloads. The ErrorInfo
payload contains a metadata
map with information about the error.
For example, here's the ErrorInfo
for a PERMISSION_DENIED
failure caused by
using credentials for a Google Cloud project where the Data Manager API isn't
enabled. The ErrorInfo
provides additional information about the error, such
as:
- The project associated with the request, under
metadata.consumer. - The name of the service, under
metadata.serviceTitle. - The URL where the service can be enabled, under
metadata.activationUrl.
{
"error"
:
{
"code"
:
403
,
"message"
:
"Data Manager API has not been used in project PROJECT_NUMBER
before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project= PROJECT_NUMBER
then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
,
"status"
:
"PERMISSION_DENIED"
,
"details"
:
[
{
"@type"
:
"type.googleapis.com/google.rpc.ErrorInfo"
,
"reason"
:
"SERVICE_DISABLED"
,
"domain"
:
"googleapis.com"
,
"metadata"
:
{
"consumer"
:
"projects/ PROJECT_NUMBER
"
,
"service"
:
"datamanager.googleapis.com"
,
"containerInfo"
:
" PROJECT_NUMBER
"
,
"serviceTitle"
:
"Data Manager API"
,
"activationUrl"
:
"https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project= PROJECT_NUMBER
"
}
},
...
]
}
}
Help
and LocalizedMessage
Check for the Help
and LocalizedMessage
payloads to get links to
documentation and localized error messages that help you understand and fix the
error.
For example, here's the Help
and LocalizedMessage
for a PERMISSION_DENIED
failure caused by using credentials for a Google Cloud project where the
Data Manager API isn't enabled. The Help
payload shows the URL where the service
can be enabled, and the LocalizedMessage
has a description of the error.
{
"error"
:
{
"code"
:
403
,
"message"
:
"Data Manager API has not been used in project PROJECT_NUMBER
before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project= PROJECT_NUMBER
then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
,
"status"
:
"PERMISSION_DENIED"
,
"details"
:
[
{
"@type"
:
"type.googleapis.com/google.rpc.LocalizedMessage"
,
"locale"
:
"en-US"
,
"message"
:
"Data Manager API has not been used in project PROJECT_NUMBER
before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project= PROJECT_NUMBER
then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
},
{
"@type"
:
"type.googleapis.com/google.rpc.Help"
,
"links"
:
[
{
"description"
:
"Google API Console API activation"
,
"url"
:
"https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project= PROJECT_NUMBER
"
}
]
},
...
]
}
}
Access error details
If you are using one of the client libraries , use the helper methods to get the standard detail payloads.
.NET
try
{
// Send API request
}
catch
(
Grpc
.
Core
.
RpcException
rpcException
)
{
Console
.
WriteLine
(
$"Exception encountered: {rpcException.Message}"
);
var
statusDetails
=
Google
.
Api
.
Gax
.
Grpc
.
RpcExceptionExtensions
.
GetAllStatusDetails
(
rpcException
);
foreach
(
var
detail
in
statusDetails
)
{
if
(
detail
is
Google
.
Rpc
.
BadRequest
)
{
Google
.
Rpc
.
BadRequest
badRequest
=
(
Google
.
Rpc
.
BadRequest
)
detail
;
foreach
(
BadRequest
.
Types
.
FieldViolation
?
fieldViolation
in
badRequest
.
FieldViolations
)
{
// Access attributes such as fieldViolation!.Reason and fieldViolation!.Field
}
}
else
if
(
detail
is
Google
.
Rpc
.
RequestInfo
)
{
Google
.
Rpc
.
RequestInfo
requestInfo
=
(
Google
.
Rpc
.
RequestInfo
)
detail
;
string
requestId
=
requestInfo
.
RequestId
;
// Log the requestId...
}
else
if
(
detail
is
Google
.
Rpc
.
ErrorInfo
)
{
Google
.
Rpc
.
ErrorInfo
errorInfo
=
(
Google
.
Rpc
.
ErrorInfo
)
detail
;
// Log the errorInfo.Reason and errorInfo.Metadata...
// Log the details in the 'Metadata' map...
foreach
(
KeyValuePair<String
,
String
>
metadataEntry
in
errorInfo
.
Metadata
)
{
// Log the metadataEntry.Key and metadataEntry.Value...
}
}
else
{
// ...
}
}
}
Java
try
{
// Send API request
}
catch
(
com
.
google
.
api
.
gax
.
rpc
.
InvalidArgumentException
invalidArgumentException
)
{
// Gets the standard BadRequest payload from the exception.
BadRequest
badRequest
=
invalidArgumentException
.
getErrorDetails
().
getBadRequest
();
for
(
int
i
=
0
;
i
<
badRequest
.
getFieldViolationsCount
();
i
++
)
{
FieldViolation
fieldViolation
=
badRequest
.
getFieldViolations
(
i
);
// Access attributes such as fieldViolation.getField() and fieldViolation.getReason()
}
// Gets the standard RequestInfo payload from the exception.
RequestInfo
requestInfo
=
invalidArgumentException
.
getErrorDetails
().
getRequestInfo
();
if
(
requestInfo
!=
null
)
{
String
requestId
=
requestInfo
.
getRequestId
();
// Log the requestId...
}
}
catch
(
com
.
google
.
api
.
gax
.
rpc
.
ApiException
apiException
)
{
// Fallback exception handler for other types of ApiException.
// Gets the standard ErrorInfo payload from the exception.
ErrorInfo
errorInfo
=
apiException
.
getErrorDetails
().
getErrorInfo
();
// Log the 'reason' and 'domain'...
// Log the details in the 'metadata' map...
for
(
Entry<String
,
String
>
metadataEntry
:
errorInfo
.
getMetadataMap
().
entrySet
())
{
// Log the metadataEntry key and value...
}
// Gets the standard RequestInfo payload from the exception.
RequestInfo
requestInfo
=
invalidArgumentException
.
getErrorDetails
().
getRequestInfo
();
if
(
requestInfo
!=
null
)
{
String
requestId
=
requestInfo
.
getRequestId
();
// Log the requestId...
}
...
}
Best practices for error handling
To build resilient applications, implement the following best practices.
- Inspect error details
- Always look for one of the standard detail
payloads
such as
BadRequest. Each standard detail payload contains information to help you understand the cause of the error. - Differentiate client from server errors
-
Determine if the error is caused by an issue with your implementation (the client) or an issue with the API (the server).
- Client errors: Codes like
INVALID_ARGUMENT,NOT_FOUND,PERMISSION_DENIED,FAILED_PRECONDITION,UNAUTHENTICATED. These require changes to the request or your application's state/credentials. Don't retry the request without addressing the issue. - Server errors: Codes like
UNAVAILABLE,INTERNAL,DEADLINE_EXCEEDED,UNKNOWN. These suggest a temporary issue with the API service.
- Client errors: Codes like
- Implement a retry strategy
-
Determine if the error can be retried, and use a retry strategy.
- Retry only
for transient server errors such as
UNAVAILABLE,DEADLINE_EXCEEDED,INTERNAL,UNKNOWN, andABORTED. - Use an exponential backoff algorithm to wait for increasing periods between retries. This helps avoid overwhelming an already stressed service. For example, wait 1s, then 2s, then 4s, continuing up to a maximum number of retries or total wait time.
- Add a small random amount of "jitter" to the backoff delays to prevent the "thundering herd" problem where many clients retry simultaneously.
- Retry only
for transient server errors such as
- Log thoroughly
-
Log the full error response, including all standard detail payloads, especially the request ID . This information is essential for debugging and reporting issues to Google support if needed.
- Provide user feedback
-
Based on the codes and messages in the standard detail payloads , provide clear and helpful feedback to your application's users. For example, instead of just "An error occurred," you can say "Transaction ID was missing" or "The account ID of the destination was not found."
By following these guidelines, you can effectively diagnose and handle errors returned by the Data Manager API, leading to more stable and user-friendly applications.

