invalid-input-response: the token siteverify would not accept
Cloudflare documents this one in five words — "Token is invalid, malformed, or expired" — and those five words cover several very different mistakes. This is how to tell which of them you made.
What siteverify is actually saying
invalid-input-response comes from POST https://challenges.cloudflare.com/turnstile/v0/siteverify, the server-side call that decides whether a token is real. It means the value you put in the response parameter was not something Cloudflare would honour.
It is not a statement about the visitor. The widget may have been solved perfectly and the token still rejected here, because everything between the widget and this call is your code.
If the token was accepted once and rejected on a second attempt, that is timeout-or-duplicate, not this. Each token validates exactly once, which is why the two codes are separate.
The causes, in the order worth checking
| Cause | How to confirm it |
|---|---|
| The token expired | Tokens are valid for 300 seconds. If you queue submissions, or a user leaves a form open, the token dies before validation. Log the gap between the widget's callback and your siteverify call. |
| You sent the sitekey instead of the token | The sitekey is public and begins 0x4; a token is far longer and begins 0. If your response value starts 0x4, that is the bug. |
| The field never arrived | An empty string is invalid input. Log the raw value your handler received before validating — a mis-named form field produces the same code as a forged token. |
| The token came from a different widget | Two widgets on one page issue two tokens against two sitekeys, and each is valid only for the secret paired with its own. |
| It was mangled in transit | Double URL-encoding, a truncating database column, or trimming to a fixed length all produce a value that is no longer the token. Compare lengths before and after. |
| The token is genuinely not real | Cloudflare's own wording notes this frequently means a fabricated token was submitted. If everything above checks out, that is what remains. |
Confirm it in one request
Before changing code, call siteverify by hand with the token your handler received. Two parameters, and it tells you plainly whether the token or your plumbing is at fault.
curl -X POST https://challenges.cloudflare.com/turnstile/v0/siteverify \ -d secret="$TURNSTILE_SECRET_KEY" \ -d response="$TOKEN_FROM_YOUR_FORM" # invalid-input-response -> the token is the problem # invalid-input-secret -> your secret is the problem # timeout-or-duplicate -> the token was already spent
A success: true here, with a failure in your application, means the token is fine and the fault is downstream. A failure here with the same token your handler logged means the token never was valid.
The full siteverify table
Seven codes, and knowing which neighbours yours narrows the search considerably.
| Code | Cloudflare's description |
|---|---|
| missing-input-secret | Secret parameter not provided |
| invalid-input-secret | Secret key is invalid or expired |
| missing-input-response | Response parameter was not provided |
| invalid-input-response | Token is invalid, malformed, or expired |
| bad-request | Request is malformed |
| timeout-or-duplicate | Token has already been validated |
| internal-error | Internal error occurred |
missing-input-response and invalid-input-response are worth distinguishing carefully: the first means the parameter was absent, the second that it was present and wrong. If you are seeing the first, the bug is in how you read the form, not in the token.
reCAPTCHA returns this string too
Google's reCAPTCHA verification endpoint uses the same code names, so a search for this error returns results for both products. If your integration is reCAPTCHA the shape of the problem is identical — expired, missing or mangled token — but the endpoint and key formats differ, so check which one you are calling before applying a fix written for the other.
Common questions
300 seconds from issue. After that siteverify returns invalid-input-response. That window is why a token should be requested at the moment of submission rather than at page load: a form left open for six minutes fails validation even though nothing about it was wrong.
invalid-input-response means the token was never acceptable — expired, malformed, empty or fabricated. timeout-or-duplicate means it was acceptable and has already been spent, because each token validates exactly once. Retrying a failed submission with the same token moves you from the first error to the second.
No. Cloudflare states each token can only be validated once and that a replayed token is rejected with timeout-or-duplicate. For retry safety use the optional idempotency key — a UUID you generate — rather than re-sending the token.
Usually a key mismatch. Testing sitekeys must be paired with testing secret keys; mixing a test key with a live secret produces a validation failure that looks like a bad token. Check the pair deployed to production belongs to the same widget.
Not necessarily, and usually not. Every ordinary cause above produces the same code — expiry, a mis-named field, a truncated column. Cloudflare's note that it often indicates a fabricated token is worth taking seriously only once the mundane explanations are eliminated.
The string is. Google's verification endpoint uses the same code names, which is why searches mix the two products. The diagnosis is similar, but the endpoint, key formats and token shape differ, so make sure the advice you follow is written for the product you are using.
Related
Sources
More in Turnstile errors
Automating a gate you own or are authorised to test?
// SolveGate clears Cloudflare Turnstile and WAF challenges through one REST call · first 1,000 solves free