Manejo de errores
Cada error de Connect llega con un código estable, una acción sugerida y un correlativo de soporte. Esta guía enseña a manejarlos; el catálogo completo vive en la referencia.
Todo error llega con la misma forma, pensada para que un humano o un agente sepan el paso siguiente sin adivinar:
{
"error": {
"code": "validation_error",
"message": "'sii.rcv.consultar' requiere una conexión concreta.",
"suggested_fix": "Pasa el connectionId de la conexión de 'sii' (MCP: campo 'connectionId' de execute; REST: header 'X-Connect-Connection'). Lístalos con la tool 'conexiones.estado.consultar'.",
"request_id": "req_5tYw2nRk88Ma"
},
"meta": { "request_id": "req_5tYw2nRk88Ma", "tool_id": "sii.rcv.consultar", "plane": "action", "latency_ms": 12, "audit_status": "recorded" }
}Las reglas
- Decide por
code, nunca por el texto.messagepuede cambiar; los códigos no. suggested_fixestá escrito para ejecutarse. Si tu agente recibe el error crudo, ya sabe qué hacer.request_idcorrelaciona con la bitácora y es lo primero que pedirá soporte. Guárdalo en tus logs.- Reintenta solo lo reintentable. Cada código declara su semántica de reintento en el
catálogo. El SDK reintenta GET por su cuenta; los
execute(POST) nunca se reintentan solos: una acción regulada reintentada a ciegas se ejecuta dos veces.
El handler de referencia
import { ConnectError } from "@emisso/connect";
try {
await connect.tools.sii.rcv.consultar(input, { connectionId });
} catch (err) {
if (!(err instanceof ConnectError)) throw err;
switch (err.code) {
case "connection_credential_required":
// La clave cambió o fue revocada: pide reconectar con un enlace nuevo.
return pedirReconexion(connectionId);
case "connection_sync_in_progress":
// Reintentable: espera y vuelve a intentar.
return reintentarLuego();
default:
log.error({ code: err.code, requestId: err.requestId }, err.suggestedFix);
throw err;
}
}Los errores que vas a ver primero
| Código | HTTP | Reintentable | Qué significa y qué hacer |
|---|---|---|---|
connection_credential_required | 428 | no | La conexión no tiene credencial viva (clave cambiada o revocada). Enlace con modo: "reconectar". |
connection_sync_in_progress | 409 | sí | Ya corre un sync de ese período. Espera y reintenta. |
scope_not_granted | 403 | no | La API key no tiene el scope de la tool. Revísala en /api-keys. Scopes vacíos significan cero autoridad, no comodín. |
validation_error | 400 | no | El input no cumple el schema; error.details trae el detalle campo a campo. También cubre el connectionId ausente del ejemplo de arriba. |
tool_not_found | 404 | no | Ese id no existe para tu organización. También cubre conectores no habilitados. |
connection_session_pending | 409 | sí | Solo BICE: el portal exige navegador y la sesión aún no se acuña. Corre la sincronización de esa conexión o espera la programada. |
rate_limited | 429 | sí | Superaste un límite. Respeta el backoff y reintenta. |
upstream_error | 502 | sí | El SII o el banco fallaron al otro lado. Reintentar suele bastar. |
El catálogo completo, con los 34 códigos agrupados por dominio y una acción por cada uno, está en la referencia de errores.
Próximos pasos
- Catálogo de errores: los 34 códigos con qué significa y qué hacer.
- Webhooks: los fallos de sincronización también llegan como evento firmado.
- Límites y planes: los números detrás de 429 y 402.
Webhooks
Un aviso firmado cuando una sincronización termina o un enlace de conexión se usa, sin sondear. El webhook nunca es load-bearing: el estado real siempre se puede consultar.
Límites
El tamaño máximo de petición, la emisión de enlaces, la cola de sincronizaciones y el cupo de llamadas por conexión. Cada número de esta página existe como constante en el código que lo aplica.