# 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.