En esta guía, se explica cómo la API de Data Manager controla y comunica los errores. Comprender la estructura y el significado de los errores de la API es fundamental para crear aplicaciones sólidas que puedan controlar los problemas de forma correcta, desde entradas no válidas hasta la falta de disponibilidad temporal del servicio.
La API de Data Manager sigue el modelo de error estándar de las APIs de Google, que se basa en los códigos de estado de gRPC. Cada respuesta de la API que genera un error incluye un objeto Status con lo siguiente:
- Es un código de error numérico.
- Es un mensaje de error.
- Son detalles adicionales opcionales del error.
Códigos de error canónicos
La API de Data Manager usa un conjunto de códigos de error canónicos definidos por gRPC y HTTP. Estos códigos proporcionan una indicación de alto nivel del tipo de error. Siempre debes verificar este código primero para comprender la naturaleza fundamental del problema.
Para obtener más detalles sobre estos códigos, consulta Guía de diseño de APIs: Códigos de error.
Soluciona errores
Sigue estos pasos cuando falle una solicitud:
Verifica el código de error para encontrar el tipo de error.
- Si usas gRPC, el código de error se encuentra en el campo
codedeStatus. Si usas una biblioteca cliente, es posible que arroje un tipo específico de excepción que corresponda al código de error. Por ejemplo, la biblioteca cliente para Java arroja uncom.google.api.gax.rpc.InvalidArgumentExceptionsi el código de error esINVALID_ARGUMENT. - Si usas REST, el código de error se encuentra en la respuesta de error en
error.statusy el estado HTTP correspondiente se encuentra enerror.code.
- Si usas gRPC, el código de error se encuentra en el campo
Verifica la presencia de la carga útil de detalles estándar para el código de error. Las cargas útiles de detalles estándar son un conjunto de mensajes para los errores de las APIs de Google. Te brindan detalles de los errores de una manera estructurada y coherente. Cada error de la API de Data Manager puede tener varios mensajes de carga útil de detalles estándar. Las bibliotecas cliente de la API de Data Manager tienen métodos de ayuda para obtener las cargas útiles de detalles estándar de un error.
Independientemente del código de error, te recomendamos que verifiques y registres las cargas útiles de
ErrorInfo,RequestInfo,HelpyLocalizedMessage.ErrorInfotiene información que podría no estar en otras cargas útiles.RequestInfotiene el ID de solicitud, que es útil si necesitas comunicarte con el equipo de asistencia.HelpyLocalizedMessagecontienen vínculos y otros detalles para ayudarte a abordar el error.
Además, las cargas útiles
BadRequest,QuotaFailureyRetryInfoson útiles para códigos de error específicos:- Si el código de estado es
INVALID_ARGUMENT, verifica la carga útil deBadRequestpara obtener información sobre qué campos causaron el error. - Si el código de estado es
RESOURCE_EXHAUSTED, consulta las cargas útiles deQuotaFailureyRetryInfopara obtener información sobre la cuota y una recomendación de demora para volver a intentarlo.
Cargas útiles de detalles estándar
Las cargas útiles de detalles estándar más comunes para la API de Data Manager son las siguientes:
BadRequest
Verifica la carga útil BadRequest cuando una solicitud falla con INVALID_ARGUMENT (código de estado HTTP 400).
Un mensaje BadRequest indica que la solicitud tenía campos con valores incorrectos o que faltaba un valor para un campo obligatorio. Revisa la lista field_violations en BadRequest para encontrar los campos que tienen errores. Cada entrada de field_violations tiene información para ayudarte a corregir el error:
fieldUbicación del campo en la solicitud, con una sintaxis de ruta de acceso en formato camel case.
Si una ruta de acceso apunta a un elemento de una lista (un campo
repeated), su índice se muestra entre corchetes ([...]) después del nombre de la lista.Por ejemplo,
destinations[0].operating_account.account_ides elaccount_iden eloperating_accountdel primer elemento de la listadestinations.descriptionEs una explicación de por qué el valor causó un error.
reasonEl enum
ErrorReason, comoINVALID_HEX_ENCODINGoINVALID_CURRENCY_CODE.
Ejemplos de BadRequest
Esta es una respuesta de ejemplo para un error INVALID_ARGUMENT con un mensaje BadRequest. El field_violations que muestra el error es un accountId que no es un número. El valor field destinations[0].login_account.account_id muestra el accountId con un incumplimiento de campo en el login_account del primer elemento de la lista destinations.
{
"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"
}
]
}
]
}
}
Esta es otra respuesta de ejemplo de un error de INVALID_ARGUMENT con un mensaje de BadRequest. En este caso, la lista field_violations muestra dos errores:
El primer
eventtiene un valor que no está codificado en hexadecimal en el segundo identificador del usuario del evento.El segundo
eventtiene un valor que no está codificado en hexadecimal en el tercer identificador de usuario del evento.
{
"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"
}
]
}
]
}
}
QuotaFailure y RetryInfo
Verifica las cargas útiles QuotaFailure y RetryInfo cuando una solicitud falla con RESOURCE_EXHAUSTED (código de estado HTTP 429).
Un mensaje QuotaFailure indica que se agotó un recurso (por ejemplo, superaste tu cuota) o que el sistema está sobrecargado. Inspecciona la lista de violations para determinar qué cuotas se superaron.
El error también puede contener un mensaje RetryInfo, que indica un retry_delay recomendado para reintentar la solicitud.
RequestInfo
Verifica la carga útil de RequestInfo cada vez que falle una solicitud. Un RequestInfo contiene el request_id que identifica de forma única tu solicitud a la API.
{
"@type": "type.googleapis.com/google.rpc.RequestInfo",
"requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}
Cuando registres errores o te comuniques con el equipo de asistencia, asegúrate de incluir el ID de la solicitud para facilitar el diagnóstico de los problemas.
ErrorInfo
Verifica el mensaje ErrorInfo para recuperar información adicional que tal vez no se capture en las otras cargas útiles de detalles estándar. La carga útil de ErrorInfo contiene un mapa metadata con información sobre el error.
Por ejemplo, aquí se muestra el ErrorInfo para una falla de PERMISSION_DENIED causada por el uso de credenciales para un proyecto de Google Cloud en el que no está habilitada la API de Data Manager. El parámetro ErrorInfo proporciona información adicional sobre el error, como la siguiente:
- Es el proyecto asociado a la solicitud, en
metadata.consumer. - Nombre del servicio, en
metadata.serviceTitle. - La URL en la que se puede habilitar el servicio, en
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.developers.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.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
}
},
...
]
}
}
Help y LocalizedMessage
Verifica las cargas útiles Help y LocalizedMessage para obtener vínculos a la documentación y mensajes de error localizados que te ayuden a comprender y corregir el error.
Por ejemplo, aquí se muestran los campos Help y LocalizedMessage para un error de PERMISSION_DENIED causado por el uso de credenciales para un proyecto de Google Cloud en el que no está habilitada la API de Data Manager. La carga útil Help muestra la URL en la que se puede habilitar el servicio, y LocalizedMessage tiene una descripción del 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.developers.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.developers.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 developers console API activation",
"url": "https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
}
]
},
...
]
}
}
Cómo acceder a los detalles del error
Si usas una de las bibliotecas cliente, usa los métodos auxiliares para obtener las cargas útiles de detalles estándar.
.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.QuotaFailure)
{
Google.Rpc.QuotaFailure quotaFailure = (Google.Rpc.QuotaFailure)detail;
foreach (
Google.Rpc.QuotaFailure.Types.Violation violation in quotaFailure.Violations
)
{
// Access attributes such as violation.Subject and violation.QuotaId
}
}
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.QuotaFailureException quotaFailureException) {
// Gets the standard QuotaFailure payload from the exception.
QuotaFailure quotaFailure = quotaFailureException.getErrorDetails().getQuotaFailure();
for (int i = 0; i < quotaFailure.getViolationsCount(); i++) {
QuotaFailure.Violation violation = quotaFailure.getViolations(i);
// Access attributes such as violation.getSubject() and violation.getQuotaId()
}
// Gets the standard RequestInfo payload from the exception.
RequestInfo requestInfo = quotaFailureException.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.
...
}
Prácticas recomendadas para el manejo de errores
Para crear aplicaciones resilientes, implementa las siguientes prácticas recomendadas.
- Inspecciona los detalles del error
- Siempre busca una de las cargas útiles de detalles estándar, como
BadRequest. Cada carga útil de detalles estándar contiene información para ayudarte a comprender la causa del error. - Diferencia los errores del cliente de los errores del servidor
Determina si el error se debe a un problema con tu implementación (el cliente) o con la API (el servidor).
- Errores del cliente: Códigos como
INVALID_ARGUMENT,NOT_FOUND,PERMISSION_DENIED,FAILED_PRECONDITIONyUNAUTHENTICATED. Estos errores requieren cambios en la solicitud o en el estado o las credenciales de tu aplicación. No vuelvas a intentar la solicitud sin solucionar el problema. - Errores del servidor: Códigos como
UNAVAILABLE,INTERNAL,DEADLINE_EXCEEDEDyUNKNOWN. Esto sugiere que hay un problema temporal con el servicio de la API.
- Errores del cliente: Códigos como
- Implementa una estrategia de reintento
Determina si se puede volver a intentar la solicitud y usa una estrategia de reintento.
- Vuelve a intentarlo solo para errores transitorios del servidor, como
UNAVAILABLE,DEADLINE_EXCEEDED,INTERNAL,UNKNOWNyABORTED. - Usa un algoritmo de retirada exponencial para esperar períodos cada vez más largos entre los reintentos. Esto ayuda a evitar sobrecargar un servicio que ya está estresado. Por ejemplo, espera 1 s, luego 2 s, luego 4 s y así sucesivamente hasta alcanzar una cantidad máxima de reintentos o un tiempo de espera total.
- Agrega una pequeña cantidad aleatoria de "fluctuación" a las demoras de la espera exponencial para evitar el problema de "activación simultánea", en el que muchos clientes vuelven a intentarlo de forma simultánea.
- Vuelve a intentarlo solo para errores transitorios del servidor, como
- Registra a fondo
Registra la respuesta de error completa, incluidas todas las cargas útiles de detalles estándar, en especial el ID de solicitud. Esta información es fundamental para depurar y, si es necesario, informar problemas al equipo de asistencia de Google.
- Proporciona comentarios de los usuarios
Según los códigos y mensajes de las cargas útiles de detalles estándar, proporciona comentarios claros y útiles a los usuarios de tu aplicación. Por ejemplo, en lugar de decir solo "Se produjo un error", puedes decir "Faltaba el ID de transacción" o "No se encontró el ID de la cuenta de destino".
Si sigues estos lineamientos, podrás diagnosticar y controlar de manera eficaz los errores que devuelve la API de Data Manager, lo que generará aplicaciones más estables y fáciles de usar.