Errors
The public API uses stable HTTP status codes and a machine-readable error envelope. SDK callers receive a typed FabHubApiError for any non-2xx response.
Error shape
{
"error": {
"code": "SCOPE_REQUIRED",
"message": "This credential is missing the items:write scope",
"request_id": "req_8f3a...",
"details": {}
}
}
request_id is included on most responses - quote it in support requests. details is present for validation errors. Branch on the stable error.code, not on message.
Status codes
| Status | Meaning |
|---|---|
400 | Invalid request or validation error |
401 | Missing, invalid, expired, or revoked credential |
403 | Missing scope, plan gate, or IP allowlist denial |
404 | Resource not found |
409 | Idempotency conflict (key reused with a different payload) |
429 | Rate limit exceeded |
500 | Server error |
Error codes
BAD_REQUEST,UNAUTHORIZED,FORBIDDEN,NOT_FOUND,CONFLICT,RATE_LIMITED,INTERNAL_ERRORSCOPE_REQUIRED- the credential lacks a required scopePLAN_REQUIRED- the tenant's plan does not include this capabilityOBJECT_ACCESS_DENIED- the referenced object is outside the tenantTENANT_DISABLED,ENDPOINT_DISABLED- kill switchesMCP_CONFIRMATION_REQUIRED- a write/destructive MCP tool needs explicit confirmation
Examples
{ "error": { "code": "NOT_FOUND", "message": "Item not found", "request_id": "req_1a..." } }
{ "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded; retry after the window resets", "request_id": "req_2b..." } }
Client guidance
Treat 401 and 403 as configuration or permission problems, not retryable failures. Treat 429 as retryable only after the rate-limit window resets. Use idempotency keys on writes so you can safely retry transport failures. See Idempotency and Rate Limits.