Praxsuite

Errores y límites

Vincent Depassier · 17 de septiembre de 2026

Las tres formas de error

POST /query devuelve un sobre estructurado:

{
  "error": {
    "code": "SCOPE_VIOLATION",
    "message": "No access to table 'invoices'.",
    "details": ["..."]
  }
}

details aparece sólo cuando hay más de una cosa que decir — típicamente una lista de fallas de validación. Programa tu cliente contra code; el mensaje es para un humano leyendo un log y puede reescribirse.

Casi todo /auth/* —registro, login, refresh, las rutas de contraseña, las de proveedores— devuelve en cambio el sobre de servicio, tanto en éxito como en error:

{
  "isSuccess": false,
  "statusCode": 400,
  "message": "Password must be at least 8 characters.",
  "data": null,
  "errors": ["Password must be at least 8 characters."]
}

Todo lo demás —la capa de autenticación, archivos, esquema, endpoints— devuelve un texto plano:

{ "error": "Origin not allowed for this credential." }

En estas dos últimas no hay code. Ramifica por el estado HTTP.

Las rutas de players son una variante chica de la forma plana, con un code al lado del mensaje: { "code": "PLAYER_NOT_FOUND", "message": "…" }. El endpoint MCP es distinto otra vez: responde en JSON-RPC.

Códigos que devuelve /query

HTTP

Código

Qué pasó

400

INVALID_REQUEST

Ni query ni mutation, o los dos a la vez

400

INVALID_REFS

refs vacío, con un GUID desconocido, con uno de otro workspace, o con más de 20 entradas

400

INVALID_QUERY / INVALID_MUTATION

El cuerpo parsea pero no tiene sentido contra el esquema

401

UNAUTHORIZED

Sin credencial, o con una que no vale para este workspace

403

FORBIDDEN

La credencial pertenece a otro workspace

403

SCOPE_VIOLATION

Una tabla del pedido está fuera de los permisos, o no se permiten agregaciones sobre ella

403

NOTIFY_DENIED

La mutación pidió anunciar en el Event Bus y la credencial no puede

408

QUERY_TIMEOUT / MUTATION_TIMEOUT

La operación pasó el tiempo máximo de ejecución

429

RATE_LIMIT_EXCEEDED

Demasiadas llamadas en este minuto

429

QUOTA_EXCEEDED

Se agotó el cupo mensual de llamadas

429

EGRESS_LIMIT_EXCEEDED

Se agotaron los bytes de respuesta incluidos en el mes

500

EXECUTION_ERROR

Falla interna; el detalle queda registrado del lado del servidor

Los tres 429 vale la pena distinguirlos en tu cliente. Un límite de tasa se despeja solo dentro del minuto y merece un reintento con backoff. Una cuota o un límite de egreso no se despeja hasta que cambia el período de facturación o alguien cambia el plan — reintentar no sirve, y lo correcto es mostrarlo.

Límites

Se miden dos cupos por workspace y por mes: llamadas a la API y egreso, los bytes que cargan tus respuestas. Los dos se ven en API Gateway → Consumo, y los dos se pueden levantar por plan o habilitando pago por uso en la configuración del gateway.

Cuando un workspace pasó sus llamadas incluidas y el pago por uso está activo, las respuestas exitosas traen tres cabeceras más para que puedas verlo:

X-Api-Usage-Overage: true
X-Api-Usage-Current: 120431
X-Api-Usage-Included: 100000

Aparte, un límite de tasa por minuto protege al workspace de un cliente desbocado. Es una propiedad del workspace, no de la clave individual.

Límites estructurales de un pedido

Esto no es facturación. Son techos fijos del gateway, y pasarse de uno es 400:

Límite

Valor

Filas que devuelve una consulta

1000 (un permiso de tabla puede bajarlo)

limit por defecto si lo omites

50

Tablas en refs

20

Profundidad de relaciones anidadas

5

Columnas en select

100

Condiciones en where

50

Profundidad de condiciones anidadas

5

Cuerpo de una llamada a un endpoint personalizado

10 MB

Pagina con limit y offset. Lee meta.limit de la respuesta en vez de asumirlo: el límite efectivo puede ser menor que el que pediste.

Caché

Una credencial se puede configurar para cachear respuestas de POST /query — sólo lecturas; un cuerpo con mutation no se cachea nunca. Con la caché activa, las respuestas traen:

Cabecera

Significado

X-Cache

HIT o MISS

X-Cache-Credential

Qué clave respondió desde su caché — sólo en HIT

ETag

Un validador que puedes devolver

Cache-Control

El modo y el TTL configurados para esa credencial

Devuelve el ETag como If-None-Match y una entrada cacheada que siga vigente responde 304 Not Modified sin cuerpo, que es la lectura más barata que hay y no gasta egreso.

Cache-Control te dice en qué modo está la credencial:

Modo

Cache-Control

Por tiempo

private, max-age=<ttl>

Invalidada por escritura

private, no-cache, must-revalidate

Híbrido

private, max-age=<ttl>, must-revalidate

Apagado

no-store

La caché se llavea por credencial —dos claves con permisos distintos nunca comparten una entrada, que es lo que hace seguro encenderla— y, en los modos que invalidan, por tabla: una escritura sobre una tabla tira las respuestas cacheadas que leían de esa tabla, y sólo esas.

Seguir

  • Query — POST /query

  • Esquema — GET /schema