Errors
Every error code the API can return, with HTTP status, common triggers, and recovery guidance.
Errors share one envelope:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Project not found"
}
}
The code is stable; the message is descriptive and may change. Treat code as the contract.
Code reference
BAD_REQUEST — HTTP 400
The request body or query string is malformed. Common triggers:
- Missing required field (e.g.
nameon agent create). - Wrong type (
label must be a string,amountCents must be an integer). - Field exceeds its length cap.
- Unknown enum value (model ID, status, visibility).
- Empty JSON body where one is required.
- Rate limit exceeded on routes that surface limits as
BAD_REQUEST(e.g. API key minting).
Recovery: fix the payload and retry.
UNAUTHORIZED — HTTP 401
No Authorization header, malformed Bearer, or the API key has been revoked. Recovery: confirm the header format Bearer alm_<env>_<...> and that the key is not revoked.
PAYMENT_REQUIRED — HTTP 402
The org cannot run a paid model because its balance is exhausted and BYOK is not configured for the requested provider. Surfaced by chat/copilot routes when assertOrgCanUsePaidModels fails. Recovery: deposit funds (POST /api/v1/billing/deposit) or add a BYOK entry for the provider.
FORBIDDEN — HTTP 403
Authenticated, but the action is not allowed. Common triggers:
- Caller has no workspace access.
- Step-up authentication required (e.g. minting API keys).
- Attempt to deactivate, re-model, or delete the default
Alaagent. - Attempt to rename, move, or delete a protected folder.
- Caller lacks billing-manage role on
PATCH /billingorPOST /billing/deposit.
Recovery: re-authenticate (for step-up), grant the user the needed role, or pick a different target.
NOT_FOUND — HTTP 404
The resource does not exist, is soft-deleted, or is invisible to the caller because of workspace scope or visibility rules. The API never reveals that a resource exists in a different org or workspace; both cases collapse to 404. Recovery: verify the ID and the caller's workspace.
CONFLICT — HTTP 409
State conflict. Examples: a concurrent update has invalidated the row, or a uniqueness constraint failed. Recovery: refetch and retry.
VALIDATION_ERROR — HTTP 422
Input shape is valid, but a value is semantically out of range. Used for nuanced field-level rejections that do not map cleanly to BAD_REQUEST. Recovery: adjust the value and retry.
TOO_MANY_REQUESTS — HTTP 429
Rate limit exceeded for a non-bypassed route. Recovery: back off, then retry. (Some endpoints surface limits as BAD_REQUEST with a Too many requests message — these are functionally equivalent.)
SERVICE_UNAVAILABLE — HTTP 503
A dependency is temporarily down (LLM provider, storage, background worker). Recovery: retry with exponential backoff.
INTERNAL_ERROR — HTTP 500
Unhandled exception. In production the message is Internal server error; in development it surfaces the original error message to aid debugging. Recovery: report the request ID and retry; if it persists, the issue is server-side.
How errors are classified
Route handlers throw subclasses of ApiError (UnauthorizedError, NotFoundError, …) which the shared errorResponse helper translates into the envelope above. Anything that is not an ApiError is logged and returned as INTERNAL_ERROR with HTTP 500. Code paths that intentionally degrade — e.g. deletion of an S3 object after the DB row was soft-deleted — are caught and ignored without surfacing an error to the client.