Errors
Every error code Ikiform returns, with its HTTP status, cause and fix.
Form submissions and the REST API share one error envelope. JSON requests get it with the matching HTTP status; browser form posts get a hosted error page with the same message and status.
The error envelope
{
"ok": false,
"error": {
"code": "rate_limited",
"message": "Too many requests. Please slow down."
},
"request_id": "req_01k7v2c9t3e8m5q4x6z0a1b2c3"
}error.codeis stable; branch on it.error.messageis plain English for people and may change.error.fieldsis present on validation errors, keyed by field id, each with a list of messages. Errors about the whole body use the key_form.error.challenge_urlis present onchallenge_required.request_idmatches theX-Request-Idheader that every response carries.- Rate-limited responses carry
Retry-Afterin seconds. Both headers are readable from browser code.
Codes
| Status | Code | Where |
|---|---|---|
| 400 | invalid_body | Submit |
| 400 | invalid_request | API |
| 401 | unauthorized | API |
| 402 | plan_required | Submit |
| 403 | forbidden | Both |
| 403 | origin_not_allowed | Submit |
| 403 | form_paused | Submit |
| 403 | captcha_failed | Submit |
| 403 | challenge_required | Submit |
| 404 | not_found | Both |
| 405 | method_not_allowed | API |
| 409 | idempotency_in_progress | Submit |
| 413 | payload_too_large | Submit |
| 415 | unsupported_media_type | Submit |
| 415 | unsupported_charset | Submit |
| 422 | validation_failed | Submit |
| 422 | files_not_supported | Submit |
| 422 | too_deep | Submit |
| 422 | idempotency_mismatch | Submit |
| 429 | rate_limited | Both |
| 429 | quota_exceeded | Submit |
| 500 | server_error | Both |
400 invalid_body
| Message | The request body could not be read. |
| Cause | Malformed JSON or multipart, a JSON array or string instead of an object, or an idempotency key over 255 characters. |
| Fix | Send one JSON object, or let the browser or FormData build the body. |
400 invalid_request
| Message | The request is invalid. |
| Cause | limit, status, form_id or cursor is invalid. The message names the parameter. |
| Fix | Use limit 1 to 100, status received or spam, a real frm_ id, and cursors exactly as returned. |
401 unauthorized
| Message | A valid API key is required. |
| Cause | No Authorization header, not a Bearer token, or an unknown, revoked or expired key. |
| Fix | Send Authorization: Bearer ik_sk_... with a live secret key. |
402 plan_required
| Message | This form isn't accepting submissions right now. |
| Cause | The workspace has no active plan. This can only happen once billing is turned on. |
| Fix | Choose a plan in the dashboard under Settings. |
403 forbidden
| Message | You do not have access to this resource. |
| Cause | The API key is malformed, belongs to another workspace, is publishable on the REST API, or lacks the needed scope. |
| Fix | Use a secret key from this workspace with the scope named in the message. |
403 origin_not_allowed
| Message | This form does not accept submissions from this site. |
| Cause | The post came from a site outside the form's allowed domains and the form rejects mismatches, or a publishable key was used from a domain not listed on the key. |
| Fix | Add the site to Allowed domains or to the key's domains. For server posts, use a secret key. |
403 form_paused
| Message | This form is not accepting submissions right now. |
| Cause | The form is paused in the dashboard. |
| Fix | Resume the form. |
403 captcha_failed
| Message | The captcha check failed. Please try again. |
| Cause | The Turnstile token is missing, expired, already used, or didn't verify. |
| Fix | Get a fresh token for every submit. With your own keys, check that the site key matches the secret. |
403 challenge_required
| Message | Complete the human check, then send the form again. |
| Cause | The form uses the Ikiform human check and a JSON post arrived without a token. |
| Fix | Call challenge(formId) from the SDK and pass the token, or use error.challenge_url. Server posts can send a secret key instead. |
404 not_found
| Message | Not found. |
| Cause | The form doesn't exist, was deleted or disabled, or the id or route is wrong. Also returned for a GET to /f/<formId>. |
| Fix | Copy the endpoint from the form's overview, and post rather than opening it in a tab. |
405 method_not_allowed
| Message | This method is not allowed here. |
| Cause | A browser preflight on the REST API, which is server to server only. |
| Fix | Call /api/v1 from your backend. |
409 idempotency_in_progress
| Message | A request with this idempotency key is still being processed. |
| Cause | A request with this idempotency key is still being processed. |
| Fix | Wait a moment and retry with the same key; you'll get the first response. |
413 payload_too_large
| Message | The submission is too large. |
| Cause | The body, a field name, a value or the number of fields is over its limit. The message says which. |
| Fix | See Limits. Split large text across fields or store files elsewhere and send a link. |
415 unsupported_media_type
| Message | Send the form as urlencoded, multipart or JSON. |
| Cause | The Content-Type isn't urlencoded, multipart or JSON, or is missing. |
| Fix | Set Content-Type: application/json when posting JSON. |
415 unsupported_charset
| Message | Only UTF-8 is supported. |
| Cause | The body isn't UTF-8, or declares another charset. |
| Fix | Encode as UTF-8. Add accept-charset="utf-8" to old HTML forms. |
422 validation_failed
| Message | Some fields are invalid. |
| Cause | Fields failed validation. error.fields maps field ids to messages. |
| Fix | Show the messages next to the fields. See Fields. |
422 files_not_supported
| Message | File uploads are not supported yet. |
| Cause | The post contains a file. File uploads are not built yet. |
| Fix | Remove file inputs, or upload files elsewhere and submit the link. |
422 too_deep
| Message | The JSON body is nested too deeply. |
| Cause | The JSON body is nested more than 3 levels deep, counting the top-level object. |
| Fix | Flatten the data, for example { "address_city": "London" }. |
422 idempotency_mismatch
| Message | This idempotency key was already used with a different payload. |
| Cause | This idempotency key was already used for this form in the last 24 hours with different fields. |
| Fix | Use a new key for new data. Keep the same key only for exact retries. |
429 rate_limited
| Message | Too many requests. Please slow down. |
| Cause | Over a rate limit. Retry-After says how many seconds to wait. |
| Fix | Wait and retry. If real visitors hit it, change the form's rate limit. |
429 quota_exceeded
| Message | This form isn't accepting submissions right now. |
| Cause | The workspace received 2 times its monthly submission limit this month. |
| Fix | Upgrade, or wait for the next month. See Monthly usage. |
500 server_error
| Message | Something went wrong on our side. |
| Cause | Something failed on Ikiform's side. |
| Fix | Retry with backoff and an idempotency key. If it keeps happening, quote request_id. |
Not errors
- Spam gets the same
201or redirect as a real submission. Look for it under the spam filter in the dashboard. - A
_redirectthat isn't allowed is ignored, and the browser lands on the hosted thank-you page. - A
_replytothat isn't one valid email address is ignored.
Retrying
- Retry
429afterRetry-After, and500,409or network errors with backoff. Send an idempotency key so a retry never creates a duplicate. - Don't retry other
4xxerrors unchanged. Fix the request first.