Errors and limits

HTTP errors, request limits and what to do when a call fails.

Error format

A failed call answers with an HTTP status code and a body. Most endpoints use this JSON envelope, with a message meant for logs and developers:

{
  "success": false,
  "data": null,
  "message": "form not found"
}

The validation queue uses a minimal shape instead — an error field — and the /mobile-collect channel answers in OpenRosa XML, an OpenRosaResponse element carrying a message, as the mobile apps expect.

Status codes

Code Meaning When it happens
400 Bad request Invalid payload or a rule the request cannot satisfy: malformed JSON, an unknown field value, a missing comment on a rejection, a registration without a verified email, or an unknown or expired refresh token.
401 Unauthorized Missing, invalid, revoked or expired session token. On the OpenRosa endpoints, the first unauthenticated probe is answered this way on purpose (WWW-Authenticate: Basic).
403 Forbidden Authenticated but not allowed: you are not a member of the workspace or project, your role is not sufficient, the permission matrix refused the action, or anonymous collection is disabled in the workspace.
404 Not found The resource does not exist, or it sits outside your access scope — a form, project, entry or collection link you cannot reach.
409 Conflict The request clashes with existing data: an email address that is already registered, a workspace slug already taken, an invitation already pending, a member already present, or a workspace membership that is not active yet.
410 Gone An invitation link that was revoked is presented again.
413 Payload too large An uploaded document exceeds the workspace size limit (see Size limits below).
422 Unprocessable entity The request is well formed but the current state forbids it: an invalid status transition, an edit of an entry that is already validated or rejected, or an invalid region code.
429 Too many requests Repeated failed one-time code (OTP) verification attempts: the address is temporarily locked. Returned by POST /auth/otp/verify — a security lockout, not a volume quota.
500 Internal server error Something failed on the server side. Retry later; if it persists, contact support.
503 Service unavailable A dependency is temporarily unavailable — sign-in provider or email delivery, for example. Retry later.
Retrying

Retry 5xx responses and network timeouts with exponential backoff. Do not retry a 4xx error unchanged — fix the request first; a 401 usually means the token must be refreshed or the caller signed in again.

Size limits

What Limit
Request bodies on the upload routes 500 MB per request (files, user documents, workspace documents).
Workspace documents The workspace setting maxDocumentSizeMb — 50 MB by default. A larger upload is rejected with 413.
Form file uploads 25 MB per file on /forms/{id}/uploads (base64 payload; JSON bodies up to 26 MB are accepted, and a file above 25 MB is refused with 400).
Mobile submissions 100 MB, advertised to KoboCollect and ODK Collect through X-OpenRosa-Accept-Content-Length.

No request quota

Zottle applies no request quota: there is no per-minute call limit and no volume-based throttling on API requests. What can fail is payload size or permissions, never throughput. One exception exists: POST /auth/otp/verify answers 429 after repeated failed attempts — a security lockout that expires on its own (see Status codes).