signalapp/Signal-Server · error · InvalidCaptchaArgumentException
invalid captcha site-key
Error message
invalid captcha site-key
What it means
Each captcha client advertises the set of valid site keys per action. verify() checks that the siteKey supplied with the request is in client.validSiteKeys(parsedAction); if not, it logs the rejection, increments the invalid-sitekey metric, and throws InvalidCaptchaArgumentException('invalid captcha site-key').
Solutions
- Update the client to use the site key configured for this server and action.
- Verify the site key is present in the server's captcha configuration (validSiteKeys for the action).
- Rotate consistently: when the site key changes in the captcha console, redeploy clients and server config together.
- Check for copy/paste or build-flavor errors placing the wrong site key in the client bundle.
Example fix
// before String siteKey = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"; // test key // after String siteKey = config.productionRecaptchaSiteKey; // key registered for this action
Defensive patterns
Strategy: validation
Validate before calling
if (!siteKey || siteKey !== config.recaptchaSiteKey) throw new Error('site key not configured for this environment'); Type guard
const isValidSiteKey = (k) => typeof k === 'string' && /^[A-Za-z0-9_-]{20,}$/.test(k); Try / catch
try { await call(captcha, siteKey); } catch (e) { if (e.message.includes('invalid captcha site-key')) { siteKey = await fetchCurrentSiteKey(); } throw e; } Prevention
- Inject site key from environment config, never hardcode
- Sync site-key rotations across server and clients
- Separate test vs production site keys per build flavor
When it happens
Trigger: A request supplies a captcha token and siteKey whose site key is not registered for that action — e.g. the client embeds a site key from a different environment, or the site key was rotated/removed server-side.
Common situations: Staging client talking to production server (or vice versa) with mismatched reCAPTCHA site keys, site keys changed in the captcha admin console but clients not updated, or a typo/placeholder site key shipped in a build.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- invalid captcha scheme
- too few parts
- invalid captcha action
- 400 Bad Request
- target-queue-size-bytes must be positive
AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09).
Data as JSON: /api/errors/e7064a3c8b3673d4.
Report an issue: GitHub.
Appendix: source
Thrown at service/src/main/java/org/whispersystems/textsecuregcm/captcha/CaptchaChecker.java:105
throw new InvalidCaptchaArgumentException("invalid captcha scheme");
}
final Action parsedAction = Action.parse(action)
.orElseThrow(() -> {
Metrics.counter(INVALID_ACTION_COUNTER_NAME).increment();
return new InvalidCaptchaArgumentException("invalid captcha action");
});
if (!parsedAction.equals(expectedAction)) {
Metrics.counter(INVALID_ACTION_COUNTER_NAME, "action", action).increment();
throw new InvalidCaptchaArgumentException("invalid captcha action");
}
final Set<String> allowedSiteKeys = client.validSiteKeys(parsedAction);
if (!allowedSiteKeys.contains(siteKey)) {
logger.debug("invalid site-key {}, action={}", siteKey, action);
Metrics.counter(INVALID_SITEKEY_COUNTER_NAME, "action", action).increment();
throw new InvalidCaptchaArgumentException("invalid captcha site-key");
}
final AssessmentResult result = client.verify(maybeAci, siteKey, parsedAction, token, ip, userAgent);
Metrics.counter(ASSESSMENTS_COUNTER_NAME,
"action", action,
"score", result.getScoreString(),
"provider", provider)
.increment();
return result;
}
}
View on GitHub (pinned to 100ab61c82)