错误码与排查

每个错误码都说明了发生了什么、该怎么处理。先判断是让访客重新验证、修正配置,还是原样重试。

错误响应的格式

接口在失败时返回非 2xx 状态码和 JSON:{"error":"invalid-input-secret"}。字段缺失或格式不对时,还会带上出错的字段:{"error":"bad-request","field":"nonce"}。请求体必须是 JSON,Secret key 放在 Authorization: Bearer 请求头里,否则会得到 unsupported-media-type secret-in-body

联系我们排查问题时,请附上响应头里的 X-Request-Id

按状态码处理

状态码含义该怎么做
400 · 409 · 413 · 415 · 422请求格式不对,或许可、token 已过期、已用、对不上代码问题先修正;验证类错误让访客重新验证(新的 intent + 重新渲染组件)
401 · 403Secret key、Site key 或域名配置不对修正配置,重试不会成功
402额度用完且余额不足充值后用同一个请求重试
408 · 429 · 503超时、限流或暂时不可用用相同参数和幂等键重试(429 按 Retry-After 等待);得到结果前不要执行业务

服务端接口错误码

来自 /intents/challenge/solve/siteverify/feedback/grants。其中 /challenge /solve 由组件调用,你通常只会在组件的错误回调里看到它们。

bad-requestHTTP 400 / 422所有接口

请求体不是合法 JSON(400),或缺少必填字段、字段类型或格式不符(422,例如 nonce 太短)。响应里的 field 会指出是哪个字段。

怎么处理:按 field 修正请求。这是代码问题,原样重试不会成功。

unsupported-media-typeHTTP 415所有接口

请求没有使用 Content-Type: application/json,例如沿用了 reCAPTCHA / hCaptcha 的表单编码请求。

怎么处理:改用 JSON 请求体,并设置 Content-Type: application/json。

secret-in-bodyHTTP 422所有接口

请求体里带了 secret 字段,这是 reCAPTCHA / hCaptcha 的写法。

怎么处理:删掉请求体里的 secret,把 Secret key 放进 Authorization: Bearer 请求头。

body-too-largeHTTP 413所有接口

请求体超过了大小上限(大多数接口为 4 KB),在读取请求时就被拒绝。

怎么处理:检查是否带了多余字段或大段数据;正常请求远小于这个上限。

payload-too-largeHTTP 413所有 JSON 接口

JSON 请求体超过了大小上限。

怎么处理:同 body-too-large:去掉多余字段,正常请求远小于这个上限。

invalid-input-secretHTTP 401/intents、/siteverify、/feedback、/grants

缺少 Secret key,或 Secret key 无效。

怎么处理:在 Authorization: Bearer 请求头里使用控制台的 Secret key(mc_sec_…)。更换密钥后旧密钥立即失效;不要误用 Site key。

origin-not-allowedHTTP 403/intents、/challenge、/solve

页面所在域名或 intent 的 hostname 不在站点的允许域名中。

怎么处理:在站点设置里加入完整域名,子域名要单独添加;本地开发请加入 localhost。

invalid-sitekeyHTTP 403/challenge

Site key 不存在,或站点已暂停、已删除。

怎么处理:核对组件的 data-sitekey,并在控制台确认站点处于启用状态。

nonce-conflictHTTP 409/intents

这个 nonce 之前用不同的 action、hostname、session 或豁免创建过许可。

怎么处理:每次新的业务操作都生成新 nonce;只有重试同一次创建时才复用 nonce,并且字段必须完全相同。

intent-expired-or-consumedHTTP 409/intents

用同一个 nonce 重试创建时,原许可已经过期(5 分钟)或已被兑换。

怎么处理:生成新的 nonce,创建新的许可。

invalid-or-expired-permitHTTP 400/challenge、/solve、/siteverify

许可不存在、已过期或已用完,或者 token 与这次兑换的 intent_id、action、hostname、站点对不上。

怎么处理:让访客重新验证:服务端创建新的 intent,重新渲染组件。不要重试同一个请求。

invalid-input-responseHTTP 400/siteverify

token 为空、格式错误、签名无效,或已超过有效期(约 2 分钟)。

怎么处理:让访客重新验证(新的 intent + 重新渲染组件)。

already-redeemedHTTP 409/siteverify

这个 token 已经被兑换过。可能是重复提交,也可能是 10 分钟后又用同一幂等键重试。

怎么处理:按验证失败处理,让访客重新验证;检查是否有重复提交。

idempotency-conflictHTTP 409/siteverify

同一个幂等键曾用于不同的 token、intent、action 或 hostname。

怎么处理:每次业务提交使用独立的幂等键;重试时所有参数必须和第一次完全相同。

insufficient-balanceHTTP 402/siteverify

本月免费额度已用完,且充值余额不足。token 没有被消耗。

怎么处理:在控制台充值后,用同一个请求重试(token 仍需在有效期内)。

challenge-expiredHTTP 400/solve

挑战在规定时间内没有完成。

怎么处理:组件会显示「重试验证」,通常无需处理;许可也过期时由服务端创建新的 intent。

invalid-solutionHTTP 400/solve

工作量证明的结果不正确。

怎么处理:组件会自动处理;持续出现时请把请求编号发给我们。

binding-mismatchHTTP 403/solve

挑战进行中,访客的网络发生了变化。

怎么处理:让访客在当前网络下重新验证。

invalid-feedbackHTTP 400/feedback

回传的业务结果不合法,例如 decision_id 不属于这个站点、时间超出范围或字段格式不符。

怎么处理:核对 decision_id(来自 /siteverify 的响应)和各字段格式。

feedback-conflictHTTP 409/feedback

同一个 event_id 已经提交过不同的内容。

怎么处理:新的事件使用新的 event_id;要修正之前的结果,用 supersedes_event_id 指向它。

invalid-or-expired-grantHTTP 400/grants、/intents

挑战豁免无效、已过期、已撤销或次数已用完。

怎么处理:不带 trusted_grant_id,创建普通 intent。

grant-conflictHTTP 409/grants

同一个 request_id 提交了不同的豁免内容。

怎么处理:重试时使用完全相同的请求;新的豁免使用新的 request_id。

rate-limitedHTTP 429所有接口

请求过于频繁。

怎么处理:按 Retry-After 等待后重试同一个请求,不要循环重试。

request-timeoutHTTP 408所有接口

请求体在规定时间内没有上传完。

怎么处理:检查网络后重试同一个请求。

unavailableHTTP 503所有接口

验证服务或它依赖的组件暂时不可用。

怎么处理:用相同的参数和幂等键重试。在得到明确结果前,不要执行业务。

not-foundHTTP 404风险数据导出、验证过程记录、控制台

资源不存在,或不属于当前账号。

怎么处理:核对站点 ID、intent ID 或订单号。

组件错误回调

组件通过 error-callback(HTML 用 data-error-callback)告诉你出了什么问题。除了下面这些,服务端的错误码(例如 origin-not-allowedinvalid-sitekey)也会原样传给回调。组件出错时会显示重试按钮,不会自动循环重试。

错误码含义怎么处理
intent-required渲染组件时没有提供 intent(data-intent 或 intent 选项)。由服务端创建 intent,把 intent_id 填进组件。
network-error组件无法连接验证服务。提示访客检查网络;组件会显示重试按钮。
request-timeout验证请求长时间没有完成,组件停止了等待。访客点击重试即可;无需重新创建 intent。
invalid-response验证服务返回了无法识别的内容,通常是代理或 CSP 拦截了请求。检查 connect-src 是否允许 https://captcha.moe,以及中间是否有代理改写响应。
challenge-expired挑战在完成前过期了。组件会显示「重试验证」;许可也过期时,服务端需要创建新的 intent 并重新渲染组件。
challenge-budget-exceeded同一个许可尝试挑战的次数用完了。服务端创建新的 intent,重新渲染组件。
unknown-error发生了未归类的错误。让访客重试;持续出现请把浏览器控制台信息发给我们。

控制台与账号

这些错误只出现在控制台和账号相关的操作里,控制台会直接显示对应的中文提示。

展开 30 个错误码
demo-unavailableHTTP 503官网试用

官网在线试用暂时不可用。

怎么处理:稍后再试;不影响你自己的站点。

unauthorizedHTTP 401控制台

没有登录,或登录已过期。

怎么处理:重新登录。

invalid-credentialsHTTP 401 / 403登录、修改密码

邮箱或密码不正确;修改密码时是当前密码不正确。

怎么处理:重新输入;忘记密码可以通过邮件重置。

email-unverifiedHTTP 403登录

邮箱还没有验证。

怎么处理:查收验证邮件并点击其中的链接;没有收到可以重新发送。

email-takenHTTP 409注册

这个邮箱已经注册过。

怎么处理:直接登录,或找回密码。

account-suspendedHTTP 403登录、邮箱验证

账号已被 captcha.moe 停用:不能登录,名下站点也暂停验证。

怎么处理:发邮件到 supports@captcha.moe 了解原因或申请恢复。

admin-protectedHTTP 409管理后台

不能在管理后台停用自己或其他管理员。

怎么处理:确需停用时,先由服务器运营方用 scripts/admin-role.sh 撤销对方的管理员身份。

invalid-emailHTTP 400注册

邮箱格式不正确。

怎么处理:检查邮箱地址。

password-too-shortHTTP 400注册

密码少于 12 位。

怎么处理:使用至少 12 位的密码。

password-lengthHTTP 400修改密码、重置密码

新密码长度不符合要求(12 到 1024 位)。

怎么处理:换一个长度合适的密码。

captcha-requiredHTTP 400注册、登录、找回密码

没有完成页面上的安全验证。

怎么处理:完成验证后再提交。

captcha-invalidHTTP 400注册、登录、找回密码

安全验证已过期或已经用过。

怎么处理:重新完成验证后再提交。

mail-unavailableHTTP 503找回密码、重发验证邮件

邮件服务暂时不可用。

怎么处理:稍后再试。

confirmation-requiredHTTP 400删除账号

删除账号时没有输入确认信息。

怎么处理:按提示输入确认内容。

balance-remainingHTTP 409删除账号

账号仍有充值余额,暂时不能删除。

怎么处理:先申请退款或用完余额。

payment-pendingHTTP 409删除账号

还有未完成的充值订单。

怎么处理:等订单完成或关闭后再删除。

refund-pendingHTTP 409删除账号

还有正在处理的退款。

怎么处理:等退款完成后再删除。

invalid-nameHTTP 400站点设置

站点名称不合法(过长或包含控制字符)。

怎么处理:换一个名称。

name-requiredHTTP 400站点设置

站点名称为空。

怎么处理:填写站点名称。

invalid-originHTTP 400站点设置

允许域名的格式不正确。

怎么处理:只填域名,例如 example.com,不含 https:// 和路径。

origins-requiredHTTP 400站点设置

至少需要一个允许域名。

怎么处理:填写表单所在的域名。

too-many-originsHTTP 400站点设置

允许域名的数量超过上限。

怎么处理:删除不用的域名,或拆分为多个站点。

invalid-modeHTTP 400站点设置

验证模式不在可选范围内。

怎么处理:从 auto、interactive、passive 中选择。

invalid-dateHTTP 400用量查询

日期格式不正确。

怎么处理:使用 YYYY-MM-DD。

invalid-rangeHTTP 400用量查询

查询的时间范围不合法或太长。

怎么处理:缩短时间范围。

order-conflictHTTP 409充值

同一个充值请求编号对应了不同的金额或内容。

怎么处理:刷新页面后重新发起充值。

pending-orders-limitHTTP 409充值

未完成的充值订单太多。

怎么处理:先完成或等待已有订单过期。

no-databaseHTTP 501控制台

服务端没有配置数据库(只会出现在开发环境)。

怎么处理:检查部署配置。

internal-errorHTTP 500控制台

服务端内部错误。

怎么处理:稍后再试;持续出现请联系 supports@captcha.moe 并附上请求编号。

常见问题排查

组件没有出现

打开浏览器控制台:脚本加载失败通常是 CSP 没有允许 https://captcha.moe;看到 intent-required 说明页面没有拿到服务端创建的 intent_id。

组件报 origin-not-allowed

页面所在的域名不在站点的允许域名里。子域名要单独添加;本地用 localhost 打开时要加入 localhost,用 127.0.0.1 打开时要加入 127.0.0.1

前端显示已验证,提交仍然失败

检查服务端是否读取了 moe-captcha-response 字段,兑换时的 intent_id、action、hostname 是否和创建时一致,以及 token 是否在 2 分钟内提交。组件显示「已验证」不代表可以放行。

控制台里的「校验成功」比「完成挑战」少很多

有些访客完成验证后没有提交表单,这是正常的。如果差得很多,通常是服务端还没有调用 /siteverify,或者兑换失败了——看一下服务端日志里的错误码。