Cloudflare Turnstile error codes
Turnstile reports failures in two places: numeric codes raised by the widget in the browser, and string codes returned by siteverify on your server. This page lists both as Cloudflare documents them today — and records what that documentation used to say, because the error table was rewritten twice between December 2025 and March 2026, and much of what is written about Turnstile errors elsewhere still describes a version that no longer exists.
How Turnstile reports errors
Turnstile surfaces problems in two different places, and knowing which one you are looking at narrows the cause immediately.
Numeric codes come from the widget itself — rendering, configuration and challenge problems. They reach you through the error-callback you passed to turnstile.render(), and they show up in the browser console.
String codes such as timeout-or-duplicate come from siteverify, the server-side validation endpoint. Those describe the token you submitted, not the widget that produced it. If you are holding one of these, the widget already did its job.
The client-side codes Cloudflare documents today
Nine numeric codes and two wildcard families, as of the revision published on 6 March 2026. A * means the remaining digits vary and are, in Cloudflare's words, for internal use.
| Code | Cloudflare's description | Retry | Our page |
|---|---|---|---|
110100 | Invalid sitekey | No | — |
110110 | Sitekey not found | No | — |
110200 | Domain not authorized | No | — |
110600 | Challenge timed out | Yes | — |
110620 | Interaction timed out | Yes | Stuck on verifying you are human |
200100 | Clock or cache problem | No | — |
200500 | Iframe load error | Yes | — |
300* | Generic challenge failure | Yes | Error 300030 |
400020 | Invalid sitekey | No | — |
400070 | Sitekey disabled | No | — |
600* | Generic challenge failure | Yes | Error 600010 |
300030 and 600010 — the two codes people actually search for — are not individually documented and never really were. They fall inside the 300* and 600* wildcards. 600010 has only ever appeared in Cloudflare's docs as a parenthetical example, and 300030 appears nowhere in them at all.
110600, 110620 and 400070 are new: they were added in the March 2026 revision and appear on almost no third-party page written before it.
The siteverify string codes
Seven strings, returned in the error-codes array of a siteverify response. This set has not changed since Cloudflare's documentation moved to its current platform in August 2024.
| Code | What it means | Our page |
|---|---|---|
missing-input-secret | You sent no secret key. | — |
invalid-input-secret | The secret key is not valid, or does not exist. | invalid-input-secret |
missing-input-response | You sent no token. Nothing was checked, because there was nothing to check. | The cf-turnstile-response field is required |
invalid-input-response | The token is malformed, expired, or was never real. | invalid-input-response |
bad-request | The request itself was malformed. | — |
timeout-or-duplicate | The token was already spent, or it has expired. | timeout-or-duplicate |
internal-error | Cloudflare could not process the request. Retry it. | — |
reCAPTCHA returns several of these strings verbatim, which is why searching one of them turns up reCAPTCHA answers. invalid-input-response, invalid-input-secret, missing-input-response and timeout-or-duplicate are shared. If you are reading an answer, check which product it is about.
If you are not sure which of these you have, start from the symptom rather than the string.
What changed, and when
Cloudflare's docs are open source, so the error table's history is public. It was rewritten twice in under ninety days, and the two rewrites disagree with each other.
The full archaeology — the six revisions, the diffs, and the 400020 bug report that made a wrong definition worse — is written up on the blog, including the claim of ours that failed verification and was dropped.
| Revision | Numeric codes listed | What happened |
|---|---|---|
| 3 Oct 2025 | 14 | The table as most of the internet still describes it. |
| 19 Dec 2025 | 33 | Twenty codes added that had never existed. Seven existing codes silently given new meanings. 600010 dropped. |
| 29 Jan 2026 | 33 | A bug report filed against one of the new meanings was fixed by making that meaning more specific — not by correcting it. |
| 6 Mar 2026 | 9 | The twenty invented codes removed, and seven real ones removed with them. Unchanged since. |
The practical consequence: any page written between 19 December 2025 and 6 March 2026 documents codes that do not exist and meanings that were never right. That window is 77 days long, and it is when a good deal of the third-party writing on this subject was refreshed.
Codes that were removed
Seven codes were documented for most of 2025, given different meanings in December, and then dropped entirely in March. Cloudflare documents none of them today.
| Code | Until 19 Dec 2025 | 19 Dec 2025 – 6 Mar 2026 | Today |
|---|---|---|---|
110420 | Invalid action | Rate limiting active | Not documented |
110430 | Invalid cData | Account suspended | Not documented |
110500 | Unsupported browser | Browser not supported | Not documented |
110510 | Inconsistent user-agent | Feature not available | Not documented |
200010 | Invalid caching | Widget already rendered | Not documented |
400030 | Invalid size | Invalid appearance | Not documented |
400040 | Invalid theme | Invalid theme | Not documented |
If a page tells you 110430 means the account is suspended, or that 110420 means rate limiting, it was written inside that 77-day window. The older meanings — invalid cData and an invalid action parameter — are the ones that match what the widget actually rejects.
Twenty codes that never existed
These were added on 19 December 2025 and removed on 6 March 2026. They appear in no revision before or after, which is a good reason to doubt they were ever emitted:
100010 100020 100030 102010 102020 102030 103010 103020 103030 104010 104020 104030 105010 105020 105030 106010 106020 120010 120020 120030
If you searched one of these and found nothing useful, that is why. If you are seeing one in production, it is not a documented code and the observable behaviour is the only thing worth debugging against.
400020, and how the drift actually happened
400020 is the clearest illustration, and the only one of the seven redefined codes to survive.
It was documented as *invalid sitekey* through 2025. The December revision changed it to *invalid widget size*. In January someone hit the code, read the new definition, and filed a documentation bug saying the list of valid widget sizes was incomplete — flexible was missing.
Cloudflare merged that fix on 29 January 2026, adding flexible to the list. The report was accurate about the sizes and beside the point about the code: 400020 had never meant invalid widget size. Five weeks later the March revision reverted it to *invalid sitekey*, where it remains.
Two independent parties therefore reasoned carefully from a definition that was wrong. That is the failure mode this page exists to prevent, and it is why every claim here carries a date.
Common questions
Cloudflare documents nine numeric codes and two wildcard families (300* and 600*), plus seven string codes returned by siteverify. That has been the set since the revision of 6 March 2026. Earlier revisions listed as many as 33 numeric codes, twenty of which were removed as never having existed.
Because there is none. Cloudflare groups it under the 300* wildcard and states that the remaining digits are for internal use. The same is true of 600010, which has only ever appeared in the docs as a parenthetical example. Both are real codes that widgets emit; neither has an entry of its own.
No. Cloudflare's documentation said that between 19 December 2025 and 6 March 2026, and it no longer says it at all. For the rest of the code's documented life it meant invalid cData — a malformed value passed in the widget's cData parameter. Pages still repeating the account-suspended meaning were written inside that window.
Several of the strings are identical. invalid-input-response, invalid-input-secret, missing-input-response and timeout-or-duplicate are returned by both products, which is why a search for one of them surfaces reCAPTCHA answers. The strings match; the causes and the fixes do not always.
Related
Sources
- Cloudflare — Turnstile client-side error codes
- Cloudflare — server-side validation (siteverify)
- cloudflare-docs #27237 — the 19 Dec 2025 error-table rewrite
- cloudflare-docs #28831 — the 6 Mar 2026 correction
- cloudflare-docs #27864 — the 400020 bug report
- cloudflare-docs #27880 — the 29 Jan 2026 fix to the wrong definition
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