Docs

Errors

What an error response looks like, what the common errors mean, and how to report one.

This page explains the errors the Tepez API returns: the shape of an error response, the two kinds of validation error, the common status codes and messages, and the request id that lets us find your request. Use it to handle errors in your code and to fix a failing request.

The error shape

Every error answers with a 4xx or 5xx status and a JSON body with three properties:

{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Could not find an entry with ID <entryId>."
}
  • statusCode repeats the HTTP status.
  • error is the status's name.
  • message says what went wrong, in words a person can read. Some errors add more properties, described below.

Base your code on the HTTP status and on the added properties, not on the text of message. The text depends on the language you ask for (see Message language) and may be reworded.

A few errors don't come from the API itself but from the network in front of it, and their body is HTML, not JSON: a request over plain HTTP, and a gateway error such as 504. Don't assume every error body parses as JSON.

This reads an entry and handles an error, keeping the request id for a support request (see The request id):

curl -i https://api.tepez.co.il/v1.0/entry/<entryId> \
  -H "x-api-key: $TEPEZ_API_KEY"

The response to an entry id that doesn't exist, with the headers trimmed:

HTTP/1.1 404 Not Found
x-tepez-request-id: 1790800000000:<host>:1:k2x9q7ab:10452
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Could not find an entry with ID <entryId>."
}

Status codes

StatusMeaningWhat to do
400The request is invalid: a parameter or a body property is missing or wrong, or the entry's data breaks the form's rules.Fix the request. See Validation errors.
401No valid credential.Send a valid key in the x-api-key header. See Troubleshooting.
403The action isn't allowed: the object belongs to another account, or its state doesn't allow the action. Also returned, with an HTML body, for a request over plain HTTP.Read message. See Troubleshooting.
404The id or the path doesn't exist.Check the id and the path, including /v1.0.
413The request body is too large.Send less data in one request. See Limits.
500The server failed to handle the request, for example because a file value points at a file that isn't in storage.Check the request's file values. Retry later. If it keeps failing, contact support with the request id.
502, 503, 504The API was unavailable or took too long to answer. The body may be HTML.Retry reads after a pause. Before retrying a write, check whether it happened. See Timeouts and gateway errors.

Validation errors

A 400 usually comes in one of two shapes, depending on what failed: the request itself, or the entry data it carries. A few 400 errors have only the three basic properties, such as Query must contain a form from an export.

An invalid request: validation

When a query parameter, a path parameter or a body property is missing or has the wrong type or value, the error adds a validation object. This request asks for more entries per page than the API allows:

curl -G https://api.tepez.co.il/v1.0/entry \
  -H "x-api-key: $TEPEZ_API_KEY" \
  --data-urlencode 'query={"form":"<formId>"}' \
  --data-urlencode 'limit=5000'
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "\"limit\" must be less than or equal to 2000",
  "validation": { "source": "query", "keys": ["limit"] }
}
  • validation.source says where the problem is: query for the query string, payload for the request body, params for the path.
  • validation.keys lists the parameters or properties that failed, as dotted paths.
  • message describes the first problem found. These messages are always in English.

The same shape comes back for a missing body property, such as a submit with no form:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "\"form\" is required",
  "validation": { "source": "payload", "keys": ["form"] }
}

and for an id that isn't 24 hexadecimal characters:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "\"entryId\" with value \"123\" fails to match the required pattern: /^[0-9a-fA-F]{24}$/",
  "validation": { "source": "params", "keys": ["entryId"] }
}

The API reference lists each endpoint's parameters and body properties.

Invalid entry data: entry_failed_validation

When the request is valid but the entry's data breaks the form's rules, the error has "id": "entry_failed_validation" and a messages array with one item per problem. Saves, submits, edits and templates can all return it. This submit leaves out a required field and sends an invalid email address:

curl -X POST https://api.tepez.co.il/v1.0/entry/submit \
  -H "x-api-key: $TEPEZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"form": "<formId>", "data": {"email": "not-an-email"}}'
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "The entry failed validation on the server. Sorry, this is probably a BUG on our side. If the issue persists please contact us at support@tepez.co.il",
  "id": "entry_failed_validation",
  "messages": [
    { "modelPath": "model['fullName']", "message": "You can't leave this empty.", "type": "error", "value": null },
    { "modelPath": "model['email']", "message": "Must be a valid email address.", "type": "error", "value": "not-an-email" }
  ]
}

Each item of messages has:

  • modelPath: the field, as a path into the entry's data.
  • message: what is wrong, in the form's language, as a person filling the form would see it, whatever language the request asks for.
  • type: error.
  • value: the value you sent, or null when the field is empty.

Nothing is stored when this error comes back. Despite the wording of the top-level message, it almost always means the data broke a rule of the form, not a fault on our side. Fix the fields named in messages and send the request again. Submit entries from your server shows how to handle it, and Form data schema shows the value each field takes.

Check the HTTP status, not the presence of id: a successful save or submit has no top-level id, and the id of this error is its code.

Message language

The locale query parameter sets the language of message. It works on every endpoint:

localeLanguage
enEnglish. The default.
heHebrew.
en_GB, en_ILEnglish.

This asks for the same missing entry in Hebrew:

curl "https://api.tepez.co.il/v1.0/entry/<entryId>?locale=he" \
  -H "x-api-key: $TEPEZ_API_KEY"
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "רשומה עם מזהה <entryId> לא נמצא."
}
  • fallbackLocales lists more locales to try, in order, for a message that has no translation in locale. Send it once per locale (fallbackLocales=he) or repeated. When no listed locale has the message, it comes back in English.
  • locale changes only message. The error name stays in English, and so do the messages of 401 errors and of invalid requests.
  • In an entry_failed_validation error, the top-level message follows locale, but the items of messages are always in the form's language.
  • Any other value fails with 400 "locale" must be one of [en, en_GB, he, en_IL].

The request id

Every response from the API, successful or not, carries an x-tepez-request-id header:

x-tepez-request-id: 1790800000000:<host>:1:k2x9q7ab:10452

It identifies the request in our logs. Log it with every failed request, and quote it when you contact support, together with the time of the request. With it we can find exactly what the API received and why it answered as it did.

Successful responses with no content

A successful request always answers 200, never 204, even when there is nothing to return. Don't expect every 200 to have a JSON body:

Timeouts and gateway errors

A 502, 503 or 504, or a request that times out on your side, means the answer didn't reach you. It doesn't mean the request failed:

  • Reads (GET) are safe to retry. Wait a few seconds, and wait longer after each retry.
  • Writes may have happened. A submit that timed out may still have stored the entry. Check before you retry, as Submit entries from your server describes, or a retry can store it twice.

Troubleshooting

ResponseCause and fix
401 Missing authenticationNo credential reached the API. Send the key in the x-api-key header, not as a query string parameter.
401 Invalid API keyThe key is mistyped, cut short, or was revoked. See Authentication.
401 Invalid token or Expired tokenA login token in Authorization is wrong, or older than 3 days. Sign in again, or use an API key.
401 Wrong username/ passwordThe email or password sent to POST /auth/login is wrong, or the user signs in with Google only.
403 You have insufficient permissions to perform the action.The object belongs to an account other than the key's. Check the id, and that the key is from the right account.
403 You cannot save this form entry because it was already submitted.Saves work only on drafts. To change a submitted entry, edit it.
403 You cannot submit this form entry because it was already submitted.The entry was submitted earlier. Nothing more to do, or edit it.
403 You cannot delete this form entry because it was already deleted.The entry was deleted earlier. Nothing more to do.
403 This form entry was already deleted and cannot be edited.The entry was deleted. Deleted entries can't change.
403 Can't change the status of the entry to this status.The edit asked for a status change that isn't allowed, such as a template to submitted. See Entries.
403 with a message the form's owner wroteGET /form/{formId}/start or a template's clone link, on a form that is closed to new entries (access.isDisabled). Ask the form's owner to reopen it.
403 with an HTML bodyThe request went over plain HTTP. Use https://.
404 Could not find an entry with ID …The id is wrong, or is the id of another kind of object, such as a form id.
404 Could not find a form with ID …The form id is wrong. Copy it from the form's link or from GET /form.
404 Not FoundThe path is wrong. Check the spelling, and that it starts with /v1.0.
413 Payload content length greater than maximum allowed: …The body is larger than the endpoint allows. The number is the limit in bytes. See Limits. Files never go in the body: upload them to storage.

Every response carries an x-tepez-request-id header. Quote it when you contact us.

Email support with the request id

Question about this page? Email support@tepez.co.il

On this page