antiwork/gumroad · error · RecaptchaUnavailableError
We couldn't load the security check. This is often caused by
Error message
We couldn't load the security check. This is often caused by an ad blocker or privacy extension — try disabling it for this page, using a private/incognito window, or switching networks, then try again.
What it means
RecaptchaUnavailableError thrown from useRecaptcha's score-based (invisible) branch when the Google reCAPTCHA Enterprise script cannot be loaded — loadRecaptchaScript(scoreScriptUrl(siteKey)) rejects — or when grecaptcha.enterprise.execute() fails to produce a token. The class itself carries no message; callers (Checkout PaymentForm, follow forms) render the shared RECAPTCHA_UNAVAILABLE_MESSAGE guidance when they catch it. It is deliberately distinct from RecaptchaCancelledError (user dismissed a challenge): this error is environmental — an extension or network is blocking Google.
Source
Thrown at app/javascript/components/useRecaptcha.tsx:145
});
});
const initPromise = loadRecaptchaScript(CHALLENGE_SCRIPT_URL).then(initRecaptcha);
initPromiseRef.current = initPromise;
// Swallow the rejection here so a blocked script doesn't surface as an unhandled promise
// rejection — execute() re-checks the stored promise and reports the failure to the user.
initPromise.catch(() => {});
}, [siteKey, scoreBased]);
const execute = () => {
if (!siteKey) return Promise.reject(new RecaptchaCancelledError());
if (scoreBased) {
return loadRecaptchaScript(scoreScriptUrl(siteKey))
.catch(() => {
// The script failing to load is environmental (blocked by an extension or the
// network), not a user dismissal — surface it as such so the UI can show guidance.
throw new RecaptchaUnavailableError();
})
.then(
() =>
new Promise<string>((resolve, reject) => {
grecaptcha.enterprise.ready(() => {
grecaptcha.enterprise.execute(siteKey, { action }).then(resolve, () => {
// Score keys never show a challenge, so there is nothing for the user to
// dismiss — a token failure here is also environmental.
reject(new RecaptchaUnavailableError());
});
});
}),
);
}
// Wait for initialization to finish before checking the widget: a submit that lands
// before the script has loaded and rendered the widget is a normal timing race, not a
// blocked CAPTCHA, so we must not report it as unavailable prematurely.View on GitHub (pinned to afeacbd394)
Solutions
- Disable the ad blocker/privacy extension for the page or use a private/incognito window — exactly what the message suggests.
- Verify the page CSP allows script-src https://www.google.com (plus frame-src/connect-src for the widget flow).
- Confirm the reCAPTCHA Enterprise site key's allowed domains include the current domain.
- Test from another network to rule out filtered connectivity to google.com.
Defensive patterns
Strategy: fallback
Type guard
import { RecaptchaCancelledError, RecaptchaUnavailableError } from "$app/components/useRecaptcha";
const isRecaptchaUnavailable = (e: unknown): e is RecaptchaUnavailableError => e instanceof RecaptchaUnavailableError;
const isRecaptchaCancelled = (e: unknown): e is RecaptchaCancelledError => e instanceof RecaptchaCancelledError; Try / catch
try {
const token = await execute();
} catch (e) {
if (isRecaptchaCancelled(e)) return; // user dismissed; retry quietly
if (isRecaptchaUnavailable(e)) {
showAlert(RECAPTCHA_UNAVAILABLE_MESSAGE, "error"); // actionable guidance
return;
}
throw e;
} Prevention
- Include www.google.com in script-src/frame-src CSP entries wherever the hook is used.
- Start loading the reCAPTCHA script on page mount, not on submit, so load failures surface earlier.
- Whitelist staging domains on the reCAPTCHA Enterprise key.
- Preserve the Cancelled vs Unavailable distinction — never show blocker guidance for a user dismissal.
When it happens
Trigger: Loading https://www.google.com/recaptcha/enterprise.js?render=<siteKey> fails: an ad blocker/privacy extension blocks it, CSP script-src doesn't allow www.google.com, the network is offline or filters Google (e.g. mainland China), or enterprise.execute() rejects (site key not valid for the domain).
Common situations: Checkout or follow-button submissions failing for a subset of buyers running uBlock/Privacy Badger; local dev with restrictive CSP; staging domains not added to the reCAPTCHA key's allowed-domain list; corporate proxies blocking third-party scripts.
Related errors
- Something went wrong.
- Something went wrong.
- ${responseData.error}
- net_negative_seller_revenue
- Something went wrong. Please refresh the page to pre-order t
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/44af4e64229ee85a.
Report an issue: GitHub.