ClouisleClouisle

API Errors and Retries

Recover API calls by HTTP status and business error codes

Every response uses the same envelope for success and failure:

{"code": 0, "data": {}, "msg": "success"}

On failure, code is non-zero and data may be null or carry structured detail (the size limit that was exceeded, the remaining login attempts, and so on). msg is localized to the request language — never branch on msg text, always branch on code.

code values come from the backend ResponseCode enum (backend/app/schemas/response.py), which is the single authoritative source for every list on this page. The HTTP status is only a transport-level hint.

HTTP Status Mapping

HTTP status and business code are not 1:1. The same code can appear with different HTTP statuses (2003 is 403 when a JWT cannot be decoded but 400 for a wrong password), so use the HTTP status for coarse classification and the body code for precise branching.

SourceHTTPBusiness code
BusinessError (default)400its own code (e.g. 5002 for username exists)
Validation errors (Pydantic)4221001
No credentials provided4012000
Invalid / revoked JWT, or single-session eviction4012001
Expired API key4012002
Inactive or pending user (auth dependency)4012004
JWT cannot be decoded or has expired4032003
Permission denied4033000 / 3001 / 3002 / 3003 / 3004
Resource not found4044000–4005, the 6000 family, 6200/6210/6211
Model quota exceeded4296103
Internal server error5001003
Generic HTTPExceptionits status1000 / 2000 / 3000 / 4000

Only 6103 (model quota) reliably returns HTTP 429. 5400 (email quota) and 5312 (TOTP attempt throttling) both return HTTP 400. Never infer rate limiting from the HTTP status; read code.

Business Code Reference

The tables below cover every error code defined by the current version. Unused numbers inside a range are reserved — do not implement branches for them.

The HTTP column lists the status the backend actually raises today. 400 means no explicit status was set, which is the BusinessError default. A few codes use different statuses on different endpoints (1004, 3001, the 6000 family, 6100); the table shows the most common value and the response is authoritative.

Codes marked “reserved” are defined in the enum but have no raise site anywhere in the backend. Do not build integrations that depend on seeing them.

General errors (1000-1999)

CodeConstantMeaningHTTP
1000UNKNOWN_ERRORUnclassified error400 (500 on the LLM processing path)
1001VALIDATION_ERRORRequest validation failed422 (Pydantic); 400 when raised manually
1002BAD_REQUESTInvalid request format or parameters400 (409 for a few conflict cases)
1003INTERNAL_ERRORInternal server error500
1004FORBIDDENGeneric forbidden operation403

For 1001, data.errors is a dictionary of field name to message array, not an array:

{
  "code": 1001,
  "data": {
    "errors": {
      "email": ["Invalid email address"],
      "password": ["String should have at least 8 characters"]
    }
  },
  "msg": "Validation error"
}

Authentication errors (2000-2999)

CodeConstantMeaningHTTP
2000UNAUTHORIZEDNo credentials provided401
2001INVALID_TOKENJWT revoked/expired, or the API key is invalid or inactive401
2002TOKEN_EXPIREDAPI key has expired (expired JWTs report 2003)401
2003INVALID_CREDENTIALSWrong username/password, or the JWT cannot be decoded / has expired403 (JWT); 400 (wrong password)
2004INACTIVE_USERUser is deactivated or pending approval401

2001 also covers the superseded token in single-session mode (msg_key is session_expired_new_login) and blacklisted tokens.

Permission errors (3000-3999)

CodeConstantMeaningHTTP
3000PERMISSION_DENIEDNo access to this resource or operation403
3001INSUFFICIENT_PRIVILEGESSuperuser privileges required403
3002NOT_TEAM_MEMBERNot a member of the target team403 (404 for POST /teams/{team_id}/leave)
3003TEAM_ADMIN_REQUIREDTeam owner or admin role required403
3004TEAM_OWNER_REQUIREDTeam owner role required403

3000 is also what an API key receives when its resource binding does not match (msg_key is api_key_no_agent_access / api_key_no_workflow_access); see the API Keys API.

Resource errors (4000-4999)

CodeConstantMeaningHTTP
4000NOT_FOUNDGeneric resource not found404
4001USER_NOT_FOUNDUser not found404
4002ROLE_NOT_FOUNDRole not found404
4003PERMISSION_NOT_FOUNDPermission not found404
4004TEAM_NOT_FOUNDTeam not found404
4005TEAM_MEMBER_NOT_FOUNDTeam membership not found404

Registration and accounts (5000-5099)

CodeConstantMeaning
5000REGISTRATION_DISABLEDOpen registration is disabled
5001ALREADY_EXISTSResource already exists (generic)
5002USERNAME_EXISTSUsername already exists
5003EMAIL_EXISTSEmail already exists
5004EMAIL_NOT_VERIFIEDEmail must be verified before signing in
5005VERIFICATION_CODE_INVALIDVerification code or reset token is invalid
5006VERIFICATION_CODE_EXPIREDVerification code or email token has expired
5007EMAIL_SEND_FAILEDEmail could not be sent (usually SMTP is not configured)
5008EMAIL_SEND_TOO_FREQUENTEmails requested too often (60-second cooldown)

This range always returns HTTP 400. 5007 may carry data and 5008 carries data.remaining_seconds for a precise message.

Duplicate conflicts (5100-5199)

CodeConstantMeaning
5100ROLE_NAME_EXISTSRole name already exists
5101PERMISSION_CODE_EXISTSPermission code already exists
5102TEAM_NAME_EXISTSTeam name already exists
5103ALREADY_TEAM_MEMBERUser is already a team member
5104DUPLICATE_NAMEDuplicate name (generic)

This range always returns HTTP 400. Retrying cannot succeed — rename the resource or switch to the update endpoint.

Forbidden operations (5200-5299)

CodeConstantMeaning
5200CANNOT_DELETE_SYSTEM_ROLESystem roles cannot be deleted
5201CANNOT_DELETE_SUPERUSERSuperusers cannot be deleted
5202CANNOT_DELETE_SYSTEM_PERMISSIONSystem permissions cannot be deleted
5203CANNOT_UPDATE_SYSTEM_PERMISSIONSystem permissions cannot be modified
5204CANNOT_MODIFY_SYSTEM_ROLESystem roles cannot be modified
5205CANNOT_DELETE_DEFAULT_TEAMThe default team cannot be deleted
5206CANNOT_ADD_AS_OWNERA member cannot be added directly as owner
5207CANNOT_CHANGE_OWNER_ROLEThe owner's role cannot be changed
5208CANNOT_PROMOTE_TO_OWNERA member cannot be promoted directly to owner
5209CANNOT_REMOVE_OWNERThe owner cannot be removed
5210OWNER_CANNOT_LEAVEThe owner must transfer ownership before leaving
5211ROLE_IN_USEThe role is still assigned to users
5212USER_ALREADY_ACTIVEUser is already active
5213USER_ALREADY_INACTIVEUser is already inactive
5214CANNOT_DEACTIVATE_SUPERUSERSuperusers cannot be deactivated

This range always returns HTTP 400. To change ownership, use the transfer-ownership endpoint described in the Teams API.

Login security (5300-5399)

CodeConstantMeaning
5300ACCOUNT_LOCKEDAccount locked after repeated login failures (5 attempts, 15 minutes by default)
5301TOO_MANY_LOGIN_ATTEMPTSToo many login attempts (reserved)
5302CAPTCHA_REQUIREDHuman verification is required
5303CAPTCHA_INVALIDHuman verification failed or the proof expired
5304PASSWORD_EXPIREDPassword has expired (reserved)
5305FORCE_PASSWORD_CHANGE_REQUIREDPassword change is required (reserved)
5306PASSWORD_MIN_AGE_NOT_METMinimum password age not reached; cannot change yet
5307PASSWORD_RECENTLY_USEDNew password matches a recent password (reserved)
5310TOTP_REQUIREDTwo-factor authentication required (reserved)
5311TOTP_INVALIDTOTP code or backup code is incorrect
5312TOTP_RATE_LIMITEDToo many failed TOTP attempts, temporarily throttled (HTTP 400)
5313TOTP_NOT_ENABLEDTwo-factor authentication is not enabled for this account
5314TOTP_ALREADY_ENABLEDTwo-factor authentication is already enabled
5315TOTP_SETUP_EXPIREDThe TOTP enrollment session expired
5316TOTP_SETUP_REQUIREDThe deployment requires enrollment first (reserved)

An expired password or an admin-forced password change is not an error: login still returns code: 0 with force_password_change: true and a reason in data. A deployment-wide TOTP requirement returns requires_totp_setup: true. See the Authentication & Login API.

Rate limiting (5400-5499)

CodeConstantMeaningHTTP
5400RATE_LIMITEDEmail quota exhausted or a provider rate limit mapped to this code400

5400 carries the dimension that was exceeded, for example {"limit": 100, "period": "hour"} for bulk email or {"requested": 3, "remaining": 1}.

Knowledge base (6000-6099)

CodeConstantMeaningHTTP
6000KB_NOT_FOUNDKnowledge base not found404
6001KB_NAME_EXISTSKnowledge base name already exists400
6002DOCUMENT_NOT_FOUNDDocument not found404
6003INVALID_DOCUMENT_TYPEDocument type is not supported400
6004DOCUMENT_PROCESSING_FAILEDDocument processing failed (reserved)—
6005CHUNK_NOT_FOUNDChunk not found404
6006DOCUMENT_PROCESSINGDocument is still processing; the operation is not available yet400
6007KB_ACCESS_DENIEDNo access to this knowledge base403

6007 mirrors 6201 for Agents: the resource exists but the current user or API key is outside its access scope. Surface a permission request instead of retrying.

Models (6100-6199)

CodeConstantMeaningHTTP
6100MODEL_NOT_FOUNDModel not found404
6101TEAM_MODEL_NOT_FOUNDTeam model authorization not found404
6102TEAM_MODEL_EXISTSThe model is already authorized for this team400
6103MODEL_QUOTA_EXCEEDEDTeam model quota (tokens or requests) exceeded429
6104MODEL_NOT_AUTHORIZEDThe team is not authorized for this model400
6105MODEL_VISION_NOT_SUPPORTEDThe model does not support vision input (reserved)—
6106MODEL_DISABLEDThe model, or the team authorization, is disabled400

6103 is the only code that reliably returns HTTP 429. 6104 and 6106 both mean “unavailable right now”, but 6104 requires adding a team model authorization while 6106 only requires re-enabling is_enabled on an existing one.

Agents and conversations (6200-6299)

CodeConstantMeaningHTTP
6200AGENT_NOT_FOUNDAgent not found404
6201AGENT_ACCESS_DENIEDNo access to this Agent403
6202AGENT_NOT_PUBLISHEDAgent is not published (reserved)—
6210CONVERSATION_NOT_FOUNDConversation not found or not owned by the caller404
6211MESSAGE_NOT_FOUNDMessage not found404

The backend does not check Agent publish status, so 6202 is reserved and never raised. Do not branch on it: unauthorized access returns 6201/3000, and an unusable model returns 6104/6106.

SSO (6300-6399)

CodeConstantMeaning
6300SSO_PROVIDER_NOT_FOUNDSSO provider is missing or disabled
6301SSO_SESSION_EXPIREDSSO login session expired (reserved)
6302SSO_REGISTRATION_DISABLEDSSO auto-registration is disabled
6303SSO_AUTHENTICATION_FAILEDSSO authentication failed (reserved)
6304SSO_INVALID_CONFIGURATIONSSO configuration is incomplete or invalid
6305SSO_PROVIDER_NAME_EXISTSProvider name already exists
6306PASSWORD_LOGIN_DISABLEDThe deployment enforces SSO and disabled password login

This range always returns HTTP 400. 6306 appears on the login endpoint, so it tells the caller to switch to SSO rather than retry.

Handling Table

HTTP / business scopeHow to handle
401, 2000-2002, 2004Log in again, refresh the JWT, or replace the expired/invalid/inactive API key; 2004 needs an administrator to restore the account
403, 3000-3004Check roles, team membership, owner/admin requirements, and the API key's Agent/Workflow bindings
404, 4000-4005, 6000/6002/6005/6200/6210/6211Confirm the resource ID, owning team, and current team context
400, 1001-1004Fix the JSON, required fields, types, or business validation; for 1001 read data.errors field by field
5000-5008Walk the user through registration, account creation, or email verification
5100-5214Do not auto-retry: rename, change the flow, or switch to an update/transfer endpoint
5300-5316Follow the lockout, captcha, password policy, or TOTP prompt
5400Back off and retry; for bulk email, reduce the recipient count
6000-6007Check knowledge base permissions, document type, processing status, and chunk IDs
6100-6106Check team model authorization, quota usage, and enabled state
6103 (HTTP 429)Back off, lower concurrency, or wait for the quota window to reset
6200/6201Confirm the Agent ID and access scope (team visibility or API key binding)
6300-6306Check the SSO provider configuration, callback, auto-registration switch, and whether password login is disabled

Retryable and Non-Retryable

Network timeouts, 503/504, temporarily unavailable providers, 5400 and 6103 throttling, and some background task failures can be retried with exponential backoff.

Do not blindly retry:

  • 1001-1004 — the request itself is invalid; a retry returns the same result.
  • 3000-3004, 6007, 6201 — permission problems; fix the authorization first.
  • 2001, 2002, 2004 — credential or account state problems.
  • 4000-4005 — the resource does not exist; verify the ID and context.
  • 5100-5214 — constraint conflicts; the request must change.
  • 6104, 6106 — model authorization or enabled state.
  • 6306 — this deployment has disabled password login.

Idempotent reads are always safe to retry. Before retrying a POST (sending a message, running a workflow, creating a resource), query the current state first to avoid duplicate writes or duplicated external side effects.

SSE Error Handling

Streaming endpoints cannot change the HTTP status once the response headers are sent, so mid-stream failures arrive as error events inside the stream:

  • After an Agent stream error event, keep the text received so far and the message_id, then decide whether to retry or surface it. The message may already be persisted, so check conversation messages before retrying to avoid duplicate questions.
  • After a workflow stream disconnects, resume with stream_url and the last received event sequence number instead of calling POST /workflows/{workflow_id}/run again.

The full event list for both streams is in Streaming Events.

How is this guide?

On this page