When a reCAPTCHA Enterprise assessment returns tokenProperties.valid as false, the backend should stop treating the response as a score decision. The token itself did not pass validation, and invalidReason is the clue for why the assessment could not be trusted.
Separate invalid tokens from risky users
A low risk score and an invalid token are different classes of result. A low score can mean the request looks suspicious even though the token is structurally valid. tokenProperties.valid=false means the assessment did not validate the token in the first place.
Google's assessment examples check tokenProperties.valid before reading the risk score, and they print or inspect tokenProperties.invalidReason when validation fails. That ordering is important: do not use score policy until the token passes validation.
The causes to check first
Start with the token path. Was the token generated by the same key family your backend is assessing? Did the frontend send the current token, or did a stale hidden field survive a form retry? Was the token consumed once already by another middleware layer? Did a mobile or webview flow strip the response before it reached the API?
Then check the key and environment. Production frontend keys paired with staging backend project settings, copied site keys from another domain, and parallel Classic-versus-Enterprise migrations all create confusing invalid-token symptoms. The browser may look fine because it can render the widget, while the backend assessment rejects the token context.
Build a debugging matrix
Log valid, invalidReason when present, returned action, expected action, hostname or app identity when present, site key label, route, frontend build, backend build, and token age bucket. Redact the raw token and credentials. Use request IDs to connect frontend and backend traces.
Group failures by route and key. If every route under one domain fails after a deploy, suspect key or project configuration. If only one SPA route fails, suspect token timing or action naming. If failures cluster in embedded browsers, inspect third-party script blocking, cookie policy, and webview navigation behavior.
Do not overpromise reason-code visibility
invalidReason can be helpful, but production debugging should not depend on every failure having a rich, stable reason string. Treat the field as one input in a broader matrix, and keep a fallback path for sparse data: token invalid, route, key, action, environment, and browser context.
That posture prevents a common support trap: telling teams to wait for a more detailed reason code while the actual fix is a mismatched site key, a stale token, or a frontend route that generates the token too early.
Fail closed with a clear retry path
If valid is false, reject the protected action or step up verification. Do not accept the form because the score is missing, and do not silently retry assessment calls with the same token. A token can be used only once; repeated backend attempts can turn a recoverable frontend issue into a duplicate-token loop.
For users, preserve form data and request a fresh verification. For engineers, alert on invalid-token rate by route and deploy version. The target is a fast, boring diagnosis: which key, which route, which action, which browser path, and which build introduced it.
Sources and further reading
Google Cloud reCAPTCHA assessment docs for tokenProperties.valid, invalidReason, action, and assessment flow.
expectedAction mismatch debugging for action contract failures.
React and SPA token expiry for frontend timing failures that can create invalid or duplicate token symptoms.
Try rCAPTCHA on your own site
Start with a minimal free testing plan, add a real site key, and see per-site verification data before moving to a paid tier.