Errors
The REST error envelope, HTTP status mapping, and a reference of every error code.
Every failed REST request returns a uniform error envelope and a meaningful
HTTP status. The status is the primary signal — clients can dispatch on it
without parsing the body. The code is the secondary signal for clients that
need to react to a specific failure mode.
The error envelope
Every failure body is shaped the same way:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message safe to surface to end users."
}
}The envelope is stable across every endpoint, including auth rejections and unknown-path 404s.
HTTP status mapping
| Status | When |
|---|---|
400 | Malformed request — missing Api-Version, bad JSON, invalid params, too many tags. |
401 | Missing or invalid Authorization header, or key without access to the library. |
404 | Organization, library, or asset not found — or an unknown REST path. |
413 | A file exceeds the per-file upload size limit. |
500 | An unexpected server fault. Logged to Sentry; safe to retry with backoff. |
4xx responses are quiet by design — they do not generate Sentry alerts.
Only 5xx is treated as a server fault.
Error codes
| Code | HTTP | When |
|---|---|---|
API_KEY_NOT_PROVIDED | 401 | The Authorization header is missing or not in Bearer <key> form. |
API_VERSION_REQUIRED | 400 | The Api-Version header is missing or empty. |
API_KEY_NOT_AUTHORIZED_FOR_LIBRARY | 401 | The key cannot reach the target library at the required access level. |
ORGANIZATION_NOT_FOUND | 404 | The :organizationId path segment does not resolve to a known org. |
RESOURCE_NOT_FOUND | 404 | The library or asset referenced by the request does not exist. |
ENDPOINT_NOT_FOUND | 404 | The REST path itself is unknown — distinct from a missing resource. |
BAD_USER_INPUT | 400 | The request body or params are invalid. Includes malformed JSON. |
PAYLOAD_TOO_LARGE | 413 | A file in the upload exceeds the per-file size limit. |
MAX_ASSETS_EXCEEDED | 400 | The upload contains more than 20 files, or the delete batch exceeds 100 ids. |
UPLOAD_ERROR_NO_FILES | 400 | The upload request carries no usable file parts. |
DELETE_ERROR | 400 | The delete request is missing ids or ids is empty. |
PRO_PLAN_CANCELED | 403 | The organization's Pro subscription has been canceled. Renew it to upload again. |
STORAGE_LIMIT_EXCEEDED | 403 | The organization's hobby (free) plan storage cap of 1 GB is reached. |
LIBRARY_LOCKED | 403 | The target library is locked because the hobby plan only includes the first 3 libraries. |
INTERNAL_SERVER_ERROR | 500 | An unexpected server fault. Sentry reported; safe to retry with backoff. |
Both the REST API and the GraphQL API return identical
HTTP status codes for the same coded error. The data layer's explicit
status (extensions.http.status) is preserved by both transports, falling
back to 401 for UNAUTHORIZED and 400 for any other known code when no
explicit status is set. The message is identical too.
Example failure responses
Missing Api-Version header:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Vary: Api-Version
{
"error": {
"code": "API_VERSION_REQUIRED",
"message": "The Api-Version header is required (current: 2026-05-20)."
}
}Invalid API key:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
Vary: Api-Version
{
"error": {
"code": "API_KEY_NOT_PROVIDED",
"message": "API Key not provided."
}
}Unknown REST path:
HTTP/1.1 404 Not Found
Content-Type: application/json
Vary: Api-Version
{
"error": {
"code": "ENDPOINT_NOT_FOUND",
"message": "The requested REST endpoint does not exist."
}
}