Requests
Troubleshooting requests
Where to look when a request was refused, an invitation never arrived, or a workflow is still waiting for a callback that already happened.
Reading an error
Every rejection carries two things: a code for the kind of failure, and a details.reason for the specific cause.
Branch on the code; read the reason to know what to fix. Where it helps, details also names the offending field,
the keys that would have been accepted, or the option keys a choice question takes.
The request methods use four codes: VALIDATION_ERROR (the call was wrong), CONFLICT (the request is in the wrong
state, or an idempotency key was reused), NOT_FOUND, and UPGRADE_REQUIRED (a plan gate or the monthly
allowance). Calling too fast returns RATE_LIMITED instead, with retryAfterMs — see
the rate limit.
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "No field with key \"company\".",
"details": { "reason": "UNKNOWN_FIELD_KEY", "field": "prefill.company", "validKeys": ["company_name", "company_size"] }
}
}Reasons you might see
Getting the call right
| Reason | What to do |
|---|---|
| FORM_NOT_PUBLISHED | Publish the form. A request pins a published version, so there has to be one. |
| UNKNOWN_FIELD_KEY | No field with that key, or it belongs in the other bucket. Every context key must be a hidden field on the published form; send free-form keys in metadata. Check fields.list; validKeys lists the accepted ones. |
| CONTEXT_KEY_NOT_HIDDEN_FIELD | You sent a visible question — or a calculated field — in context. Visible questions go in prefill; calculated fields cannot be set at all. |
| INVALID_PREFILL_VALUE | Wrong shape for that question type. expectedType says what was wanted; for choice questions, send the option key, not the label; a matrix takes { "row_key": "column_key" }. expectedType "not_prefillable" means the field takes no caller value — a file, signature, payment, appointment, or calculated field. |
| READONLY_REQUIRES_PREFILL | A locked key has no value. Every key in readonly must also be in prefill. |
| READONLY_REQUIRED_EMPTY | A required field is locked with an empty value — the recipient could never submit. Supply a value or stop locking it. |
| LANGUAGE_NOT_PUBLISHED | That language is not published on the current version. validKeys lists the ones that are. |
| INVALID_REMINDER_SCHEDULE | An offset could not be read, the same offset appears twice, or there are more than five steps. Use positive whole days, hours or minutes: 2d, 12h, 30m. |
| EXPIRY_OUT_OF_RANGE | expiresAt is in the past or more than 365 days out. |
| CALLBACK_URL_NOT_ALLOWED | The URL is not HTTPS, carries credentials, or resolves to a private address. Localhost will not work — use a tunnel. |
| DOMAIN_NOT_ALLOWED | That custom domain is not active, or belongs to another workspace. |
| INVALID_DOCUMENT_TARGET | The form has no Documents block, or it has more than one and you did not name which with field. validKeys lists the block keys. |
| DOCUMENT_NOT_UPLOADED | The upload was reserved but the bytes never arrived. PUT the file to its uploadUrl first. |
| DOCUMENT_INVALID | The uploaded bytes disagree with the size, type or sha256 documents.create declared, or the type is not a PDF or image. |
| DOCUMENTS_TOO_MANY | The block would show more than 20 documents, counting the authored ones. |
| DOCUMENTS_TOO_LARGE | One request may carry 100 MB of documents in total, and 25 MB per document. |
| SCOPE_REQUIRED | Listing requests needs a workspace or a form to scope the list to. |
| RECIPIENT_EMAIL_REQUIRED | Email delivery or reminders need recipient.email. |
| UPGRADE_REQUIRED | The plan does not include the feature — reminders are Pro or Business, and a guest account cannot email invitations. |
| FREE_INVITATIONS_USED | This Free account has spent its 10 free invitations, for good. Create the request with "delivery": "none" and send the link yourself, or upgrade to Pro. |
| MONTHLY_ALLOWANCE_REACHED | The workspace has spent this month's allowance of submissions and requests. Every request costs one unit when it is created, answered or not. Requests you already created can still be answered; new ones wait for the 1st of the month (UTC) or an upgrade. |
Acting on an existing request
| Reason | What to do |
|---|---|
| REQUEST_NOT_FOUND | No request with that id in a workspace this token can reach. |
| REQUEST_NOT_PENDING | Already completed, expired, or canceled. You cannot remind or cancel a finished request. |
| REMINDER_TOO_SOON | A manual reminder went out less than ten minutes ago. details.retryAfterMs says how long to wait. |
| REMINDER_CAP_REACHED | This request has had all eight reminders it will ever get, manual and scheduled together. |
| TEST_REQUEST | You asked formbase to email a test request. Nothing is ever emailed for one — open its link yourself instead. |
| REQUEST_NOT_TERMINAL | You asked to replay a callback for a request that is still pending. There is nothing to replay yet. |
| NO_CALLBACK_TO_REPLAY | The request was created without a callbackUrl. |
| IDEMPOTENCY_CONFLICT | That key was used for a different body. Use a new key, or send the original body again unchanged. |
The invitation never arrived
Open the request in the Requests page and read the timeline. The first invitation line tells you which case you are in.
| Timeline says | What it means | What to do |
|---|---|---|
| Invitation queued | Accepted, not sent yet. | Give it a minute. If it stays queued, check the request has a recipient email. |
| Invitation delivered | Handed to the email provider. | Ask them to check spam. Sending from your own domain helps — see custom email domains. |
| Invitation failed | formbase could not send it — or the provider bounced it, or the recipient marked it as spam. | Read deliveryStatus on requests.get: "failed" is usually a plan or address problem, so fix it and send a reminder, which carries the same link (on Free, copy the link and send it yourself). "bounced" means the address is wrong or dead — create a new request for the right address; reminding will not help. |
No timeline entry at all
Then no email was ever asked for. The request was created with delivery: “none” — deliver the link yourself, or create a
new request with delivery: “email”.
Invitations and reminders share a budget of ten emails per day per form and recipient address, and a request never emails its recipient more than nine times in its life — one invitation and up to eight reminders.
The callback never landed
The request drawer’s Callback section shows the URL and the outcome. Callback failed after N attempts means formbase tried and gave up — eight attempts over about four hours.
Check the URL. It is shown in the drawer. A workflow tool’s resume URL belongs to one run, and a run that was deleted or re-created no longer answers on it.
Check what your endpoint returned. Anything outside 2xx is a failure. A 4xx other than 408 or 429 stops the retries immediately — formbase reads it as “your endpoint rejected this”, and re-sending identical bytes cannot change that.
Fix the receiver, then press Replay. The same payload goes out again with the same event id, so a receiver that deduplicates is safe.
Signature check failing?
Almost always the raw body. If you parse the JSON and re-serialize it before hashing, the bytes differ and the signature will never match. Hash the body exactly as it arrived. The other common cause is a regenerated signing secret that the receiver has not picked up — there is no grace period.
Other things people hit
The recipient says the link shows a notice, not the form. The request is terminal — completed, expired, or canceled. That is the outcome page. Create a new request if they need another go.
An automation stopped matching after an edit — an answer went missing from the callback, or
requests.createbegan refusing a key withUNKNOWN_FIELD_KEY. A published field key disappeared: someone retyped it, or deleted the question and added a new one in its place. Retitling is safe; both of those are not. Type the old key on the field (toolbar key icon → Keys) and publish again. Publish warns before this happens — see When a published key is about to disappear.Prefill for a file upload or a signature is refused. Those cannot be supplied by a caller —
fields.listmarks themprefillable: false.Two requests appeared for one workflow run. The run retried without an
idempotencyKey. Pass the execution id as the key.