Guides
Errors and limits
Every failure answers with the same document and a code that does not change. Branch on the code, show the detail.
The error document
Errors are RFC 9457 problem documents, served as application/problem+json with the matching HTTP status.
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"code": "validation_failed",
"detail": "the request is invalid",
"errors": [
{ "field": "port", "message": "must be between 1 and 65535" }
]
}| Field | Meaning |
|---|---|
code | What kind of error this is, as a stable identifier. This is what code should test. |
detail | A sentence for a person, saying what went wrong and, where it helps, what to do. |
status | The HTTP status, repeated. |
errors | On validation errors only: one entry per invalid field, with its name and message. |
type, title | Always about:blank and the status's standard phrase. |
Codes
The codes below can come from any endpoint. Those specific to one endpoint are listed with its responses in the reference.
| Status | Code | When |
|---|---|---|
400 | (various) | The request cannot be acted on as it is. The code names why, per endpoint: passkey_expired, not_impersonating… |
401 | unauthenticated | No credential, or one that is unknown, expired or revoked. |
401 | invalid_credentials | The email or password is wrong. Deliberately does not say which. |
401 | invalid_code | The two-factor or recovery code is wrong, or was already used. |
401 | mfa_required | The session has passed the password and waits for its second factor. |
403 | forbidden | The caller is known but its role is too low, or the request comes from another site. |
403 | confirmation_required | A secret is being read back: the session must confirm its identity first. |
403 | signups_closed | New accounts cannot be created right now. |
403 | suspended | The account was suspended by the platform's operators; the detail says why. |
404 | not_found | No such thing, or nothing the caller may see. The two are not told apart, so names cannot be probed. |
409 | (various) | The request conflicts with what exists: name_taken, bucket_not_empty, tunnel_limit, not_in_progress… Listed on each endpoint. |
422 | validation_failed | One or more fields are invalid. `errors` lists each field and what is wrong with it. |
429 | rate_limited | Too many attempts. `Retry-After` gives the seconds to wait. |
501 | not_configured | This deployment runs without that product: no storage engine, no node for deployments, no GitHub App. |
503 | maintenance | The platform is closed for maintenance. What is deployed keeps being served; the API comes back by itself. |
500 | internal | A fault on the platform's side. Nothing in the detail is meant to be parsed. |
What is safe to retry
- GET, PUT and DELETE can be repeated: asking twice leaves things as asking once.
- Creating by name (a service, a bucket, a tunnel with a name) is safe to repeat too: the second attempt answers
409 name_takenrather than making a second one. Tunnel creation acceptsreuse: trueto get the existing one back instead. - Starting a deployment is not: each call queues one.
- On
429, wait forRetry-After. On5xxand network failures, retry with increasing pauses.
Limits
| Limit | Value |
|---|---|
| Request body | 1 MiB of JSON. Objects go to the storage endpoint, which has no such limit. |
| Request duration | 30 seconds. |
| Sign-in attempts | 30 per address in 5 minutes; 10 per email in 15 minutes. |
| Second-factor and confirmation attempts | 8 per account in 10 minutes. |
| Sign-ups | 10 per address per hour. |
| Services per workspace | Shown in the 409 service_limit answer when reached. |
| Tunnels per workspace | 100. |
| Machines per workspace | 50. |
| Buckets per workspace | 50, with 20 access keys each. |
| Variables per service | Shown in the validation error when exceeded. |
| Operations signed at once | 1,000 object URLs per call, valid from a minute to a week. |
| Runtime log | The most recent 5,000 lines per service. |
Listings that can grow without bound (requests, events, audit entries) take a limit and return the newest first; the reference says how each continues.