turnstile · error reference

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.

Turnstile error 300030Error 300030 means a Turnstile widget mounted and then stopped responding. The real causes, the codes it gets confused with, and the fixes.Turnstile timeout-or-duplicate errorsiteverify returns timeout-or-duplicate when a Turnstile token is verified twice or is older than 300 seconds. The causes, and how to fix each one.Turnstile callback not firingWhy the Turnstile success callback never runs: implicit rendering, callbacks not on window, hidden containers and SPA remounts.Cloudflare Turnstile error 600010Turnstile error 600010 is a generic challenge failure in the 600* family. What Cloudflare documents, the reproduced causes, and how to fix it.cf-turnstile-response invalidThree different failures wear this name. Sort out which one you have — the token never arrived, siteverify refused it, or your keys do not match.Turnstile stuck on "Verifying you are human"Why Turnstile hangs on "Verifying you are human": how to read the error code, plus fixes for CSP, clock skew, blocked domains and headless CI.invalid-input-responsesiteverify returns invalid-input-response when a token is invalid, malformed or expired. The causes worth checking, in the order they occur.invalid-input-secretsiteverify returns invalid-input-secret when your secret key is rejected. Why the key is usually right, and the five things that actually cause it.Token rejected"Token rejected" is not a Cloudflare error — it is what an app prints when siteverify refused its token. What to do, as a visitor or as a developer.Field is requiredA Laravel validation message meaning the Turnstile token never reached your server. Why the field is empty, how to tell which cause it is, and the fix for each.Turnstile 401 in consoleA 401 on a /cdn-cgi/challenge-platform/ pat/ request is expected. Cloudflare documents it: the browser could not get a Private Access Token, and falls back.Turnstile verification loopThe widget completes, then challenges again. Cloudflare calls it a challenge loop. The five documented causes, how to tell them apart, and what each one fixes.Turnstile script fails to loadapi.js never runs, or turnstile is undefined when you call render. The four causes worth checking first, starting with the one nobody expects: Rocket Loader.

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.

CodeCloudflare's descriptionRetryOur page
110100Invalid sitekeyNo—
110110Sitekey not foundNo—
110200Domain not authorizedNo—
110600Challenge timed outYes—
110620Interaction timed outYesStuck on verifying you are human
200100Clock or cache problemNo—
200500Iframe load errorYes—
300*Generic challenge failureYesError 300030
400020Invalid sitekeyNo—
400070Sitekey disabledNo—
600*Generic challenge failureYesError 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.

CodeWhat it meansOur page
missing-input-secretYou sent no secret key.—
invalid-input-secretThe secret key is not valid, or does not exist.invalid-input-secret
missing-input-responseYou sent no token. Nothing was checked, because there was nothing to check.The cf-turnstile-response field is required
invalid-input-responseThe token is malformed, expired, or was never real.invalid-input-response
bad-requestThe request itself was malformed.—
timeout-or-duplicateThe token was already spent, or it has expired.timeout-or-duplicate
internal-errorCloudflare 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.

RevisionNumeric codes listedWhat happened
3 Oct 202514The table as most of the internet still describes it.
19 Dec 202533Twenty codes added that had never existed. Seven existing codes silently given new meanings. 600010 dropped.
29 Jan 202633A bug report filed against one of the new meanings was fixed by making that meaning more specific — not by correcting it.
6 Mar 20269The 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.

CodeUntil 19 Dec 202519 Dec 2025 – 6 Mar 2026Today
110420Invalid actionRate limiting activeNot documented
110430Invalid cDataAccount suspendedNot documented
110500Unsupported browserBrowser not supportedNot documented
110510Inconsistent user-agentFeature not availableNot documented
200010Invalid cachingWidget already renderedNot documented
400030Invalid sizeInvalid appearanceNot documented
400040Invalid themeInvalid themeNot 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:

text
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

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