# Errores Toda llamada fallida devuelve la misma forma JSON y un estado HTTP estándar. El SDK convierte cada uno en una excepción de Python, así su código maneja un significado, no un número. ## El cuerpo del error [#el-cuerpo-del-error] Los errores siguen el RFC 9457 y se envían como `application/problem+json`: ```json { "type": "https://klarety.ai/problems/too-many-requests", "title": "Too many requests", "status": 429, "detail": "slow down and retry in 12s", "instance": "/v1/sql" } ``` | Campo | Significado | | --- | --- | | `type` | Una dirección estable para este tipo de problema. Es seguro decidir con base en ella. | | `title` | Un resumen corto. | | `status` | El estado HTTP. | | `detail` | Qué pasó, en palabras que puede mostrar o registrar. | | `instance` | La ruta llamada. | | `credits` | Si aparece: lo que costaría la acción rechazada, para que una persona acepte el precio y pida de nuevo. | | `limit` | Si aparece: el límite del plan que la rechazó, para que una persona pida aumentarlo. | ## Códigos de estado [#códigos-de-estado] | Estado | Significado | ¿Reintentar? | | --- | --- | --- | | `401` | Falló el inicio de sesión: sin token, un token incorrecto o vencido, o una clave rechazada. El cuerpo es igual para toda causa. | No. Corrija la clave u obtenga un token nuevo. | | `402` | El espacio de trabajo no puede pagar este trabajo. | Después de agregar créditos. | | `403` | Inició sesión, pero esto está fuera del alcance de su clave o rol. | No. | | `404` | No existe, o no le corresponde verlo. | No. | | `409` | Cambió desde que lo leyó, o está cambiando. | Lea de nuevo y reintente. | | `413` | El cuerpo de la solicitud es demasiado grande (más de 1 MiB). | No. Envíe menos, o suba un archivo. | | `422` | La solicitud no es una que usted pueda hacer, o no es válida. | No. Corrija la solicitud. | | `429` | Demasiadas solicitudes, o todos los espacios ocupados. No se ejecutó nada. | Sí, después de `Retry-After` segundos. | | `500` | Algo falló de nuestro lado. El cuerpo no trae detalle. | Sí, un poco más tarde. | | `503` | No disponible por el momento, por ejemplo mientras Nexus arranca. | Sí, después de `Retry-After` cuando aparece. | ## Cómo los lanza el SDK [#cómo-los-lanza-el-sdk] Todas las excepciones del SDK heredan de `KlaretyError`, y se importan desde `klarety`. | Excepción | Se lanza por | | --- | --- | | `AuthError` | `401`, y una clave rechazada en `Nexus.connect()`. | | `RefusedError` | `403` y `422`. | | `TableRuleError` | Un cambio que incumple una regla de la tabla (un tipo de `RefusedError`). Nunca lo reenvíe igual. | | `NotFoundError` | `404`. | | `ConflictError` | `409`. | | `InsufficientCreditsError` | `402`. | | `OverBudgetError` | `413`, `429`, y una consulta que leería más de lo que permite su plan. | | `RateLimitedError` | Más llamadas por minuto de las que permite su plan (un tipo de `OverBudgetError`). | | `ServiceError` | `500`, `503` y cualquier otra falla de nuestro lado. | | `AnswerNotReadyError` | Sin respuesta en el tiempo permitido, a menudo mientras Nexus arranca (un tipo de `ServiceError`). | | `SparkStartingError` | Spark está arrancando para su espacio de trabajo (un tipo de `AnswerNotReadyError`). | | `WaitingForOwnerError` | Un cambio está en espera del visto bueno del propietario. Trae `job_id`. Nunca lo reenvíe. | ### Un manejo cuidadoso [#un-manejo-cuidadoso] ```python from klarety import ( AuthError, ConflictError, InsufficientCreditsError, KlaretyError, Nexus, OverBudgetError, RefusedError, ServiceError, ) try: with Nexus.connect() as nexus: result = nexus.sql("SELECT COUNT(*) AS n FROM orders") print(result.rows) except AuthError: print("Sign-in failed: check or replace the API key.") except InsufficientCreditsError: print("Out of credits.") except OverBudgetError as over: print(f"Over a plan limit or rate: {over}") except RefusedError as refused: print(f"Not allowed: {refused}") except ConflictError: print("Changed since read: read again, then retry.") except ServiceError as failed: print(f"Klarety could not answer, try later: {failed}") except KlaretyError as other: print(f"Klarety error: {other}") ``` El orden importa: capture primero las excepciones más específicas. ## Lo que el SDK reintenta por usted [#lo-que-el-sdk-reintenta-por-usted] Rara vez necesita su propio ciclo de reintentos. - **Las lecturas** (`GET`) se reintentan hasta tres veces ante `502`, `503` y `504`, con una espera corta. - **Las respuestas de ocupado o de límite de solicitudes** se esperan en cualquier llamada, respetando `Retry-After`, hasta por cinco minutos. No se ejecutó nada, así que es seguro. - **Las sentencias SQL** llevan un ID, así que una sentencia reenviada se ejecuta una sola vez. - **Las demás escrituras** (`POST`, `PUT`, `PATCH`, `DELETE`) nunca se reintentan, porque repetir una podría gastar créditos dos veces. ## Reintentos con HTTP directo [#reintentos-con-http-directo] Si llama a la API directamente: 1. Reintente solo ante `429`, `503` y `500`. 2. Espere los segundos del encabezado `Retry-After` cuando aparece; si no, espere un tiempo creciente con variación aleatoria. 3. Reintente una escritura solo si es seguro ejecutarla dos veces, o si lleva su propio ID (`statement_id` en `/v1/sql`, `write_id` en ediciones de filas). ## Próximos pasos [#próximos-pasos] - [Límites y límites de solicitudes](/docs/es/developers/limits) para ver qué provoca `429` y `413`. - [Autenticación](/docs/es/developers/authentication) para `401`. - [Referencia de la API](/docs/es/developers/api-reference) para todos los endpoints.