Troubleshooting
Cloudflare Turnstile Siteverify Errors: Why a Token Is Rejected
Every Cloudflare Turnstile siteverify error code with Cloudflare's meaning and fix, and why a site rejects a token when you automate a form.
By ZeroCaptcha Engineering6 min readPublished Updated
Cloudflare Turnstile’s siteverify API rejects a token with one of seven error codes:
missing-input-secret, invalid-input-secret, missing-input-response,
invalid-input-response, bad-request, timeout-or-duplicate and internal-error. Only two
are about the token itself: timeout-or-duplicate (“Token has already been validated”, and also
what an expired token gets) and invalid-input-response (“Token is invalid, malformed, or
expired”). A token can also pass siteverify and still be refused, because the site compares the
reply’s action or hostname with what it expects, or never finds the token where it looks.
The site’s server makes the siteverify call, so when you automate a form you rarely see these codes: you see the site’s own error message. This article lists each code with Cloudflare’s wording, then maps each cause to what you, the developer automating the form, can change. Only automate sites you are allowed to; see responsible captcha automation.
Every Cloudflare Turnstile siteverify error code
Cloudflare’s complete list, with its description and required action verbatim (checked 1 October 2026), and who can act on it:
| Error code | Cloudflare’s description | Cloudflare’s action | Who can fix it |
|---|---|---|---|
missing-input-secret |
“Secret parameter not provided” | “Ensure secret key is included” | The site |
invalid-input-secret |
“Secret key is invalid or expired” | “Check your secret key in the Cloudflare dashboard” | The site |
missing-input-response |
“Response parameter was not provided” | “Ensure token is included” | You, if the token was not in the field the site reads |
invalid-input-response |
“Token is invalid, malformed, or expired” | “User should retry the challenge” | You: send a new, complete token |
bad-request |
“Request is malformed” | “Check request format and parameters” | The site |
timeout-or-duplicate |
“Token has already been validated” | “Each token can only be used once” | You: one fresh token per submission |
internal-error |
“Internal error occurred” | “Retry the request” | The site retries; you can resubmit with a new token |
Three rules about the call itself explain the site-side codes. Siteverify is
POST https://challenges.cloudflare.com/turnstile/v0/siteverify, and “The API accepts both
application/x-www-form-urlencoded and application/json requests, but always returns JSON
responses”, so a GET-style check copied from another CAPTCHA does not fit it. It needs secret and
response. And it should be called only from the site’s backend.
What a Cloudflare Turnstile token is covers the full request
and reply.
Why a token is rejected when you automate a form
Expired or reused: timeout-or-duplicate
Cloudflare gives a token a “Validity period: 300 seconds (5 minutes) from generation” and makes
it “Single use”. The server-side docs say a replayed token “will be rejected with the
timeout-or-duplicate error code”, and that a form submitted after the 300 seconds gets the same
code. In automated code, this usually means a token was solved too early, shared between two
requests, or reused on a retry after the site refused the first attempt for another reason, such
as a wrong password.
What you can change: create the task when your code reaches the form, submit as soon as the
token is ready, and get a new token for every attempt. ZeroCaptcha’s ready reply includes
expiresAt, so your code can check the time left before submitting. The patterns are in
Cloudflare Turnstile token expiry.
A damaged or wrong token
invalid-input-response, “Token is invalid, malformed, or expired”, covers a token that was cut
short or altered on its way to the site. A token can be up to 2,048 characters, so a field, a
column or a URL that truncates it breaks it; so does URL-encoding it twice. The testing dummy
token XXXX.DUMMY.TOKEN.XXXX fails too: “Production secret keys will reject the dummy token.”
Each widget has its own sitekey and secret key, and the site verifies with its widget’s secret. A token solved for a different sitekey, such as the sign-up widget’s when you submit the login form, or a sitekey your code cached before the site changed it, is not a token for this widget. Cloudflare does not document which code that case returns; expect a failure.
What you can change: read the sitekey from the page at run time, from the widget inside the form you submit (find a Cloudflare Turnstile sitekey), and pass the token through unchanged.
Action and hostname checks on the site’s side
Siteverify returns action, cdata and hostname with every result, and Cloudflare’s best
practices tell sites to use them: “Check additional fields. Validate the action and hostname when
specified.” Its own sample code does exactly that, with lines such as
if (expectedAction && validation.action !== expectedAction) {. A site that follows it rejects a
token whose action differs from the widget’s, even though siteverify said success: true.
Siteverify returns no error code for this; the refusal is the site’s.
What you can change: copy the widget’s data-action (or the action option passed to
turnstile.render()) into the task’s action, and its data-cdata into cdata. Cloudflare
limits action to 32 and cData to 255 characters, alphanumerics plus _ and -.
Cloudflare Turnstile action and cData shows where
to find both. For the hostname, “Hostname where the challenge was served”, use the exact URL of
the page that shows the widget as websiteURL, including its subdomain.
The token never reached siteverify: the field name
missing-input-response means the site’s server called siteverify without a token. When you
automate, the usual cause is that the token went into a field the server does not read. The
widget’s input is named cf-turnstile-response by default, but sites can rename it
(response-field-name), turn it off (response-field) and send the token from JavaScript, or run
Turnstile in reCAPTCHA compatibility mode, where the input is g-recaptcha-response.
What you can change: submit the form once by hand with the browser’s developer tools open and copy the field name from the real request. Submit a Cloudflare Turnstile token covers form fields, callbacks and JSON bodies.
Errors that are the site’s to fix
missing-input-secret, invalid-input-secret and bad-request come from the site’s own request,
and nothing in your submission changes them. internal-error is Cloudflare’s; its action is
“Retry the request”, and sites can retry safely with an idempotency_key, “A UUID you generate to
safely retry validation requests”. If the site shows an error after a Cloudflare problem, submit
again later with a new token.
When the site is yours
If you run the site and your own users are refused, log the error-codes array from every
failed siteverify reply, and test each branch with Cloudflare’s testing keys: the secret
2x0000000000000000000000000000000AA always fails validation, and
3x0000000000000000000000000000000AA returns the “token already spent” error. In our own check on
30 September 2026 (an observation, not Cloudflare’s documentation), siteverify answered the dummy
token with invalid-input-response under the 2x secret and timeout-or-duplicate under the
3x secret. Test Cloudflare Turnstile in CI wires the
keys into a test suite.
What a solving API can and cannot fix
A solving API fixes one thing: getting a valid token for the page when your client cannot produce
one. ZeroCaptcha returns a token for the websiteURL, websiteKey, action and cdata you send,
usable once within 300 seconds. It cannot fix a submission under the wrong field name, a token
held past expiresAt, or the site’s own secret-key errors. Tasks that fail cost nothing; a token
you let expire was solved, so it is charged, and getTaskResult then answers
ERROR_TOKEN_EXPIRED.
Don’t confuse siteverify’s codes with the solving API’s own codes, such as
ERROR_CAPTCHA_UNSOLVABLE: those are covered in
CAPTCHA API error codes and the
errors reference. The full solving flow is on the
Cloudflare Turnstile solver page.
See the codes for yourself
The Cloudflare Turnstile token checker asks
siteverify about a token from any of this site’s demo widgets and explains each code it returns.
Check the same token twice to see timeout-or-duplicate.
Sources
- Cloudflare Turnstile: server-side validation (checked 1 October 2026).
- Cloudflare Turnstile: widget configurations (checked 1 October 2026).
- Cloudflare Turnstile: migrating from reCAPTCHA (checked 1 October 2026).
- Cloudflare Turnstile: testing (checked 1 October 2026).
The team that builds and runs the ZeroCaptcha API. Articles are drafted with AI tools, then checked against the API's code and the primary sources each one cites.