跳到主要内容

故障排查

按 HTTP 状态码 / facilitator 错误码归类,列出付费 Agent 最常见的失败模式。


HTTP 状态码

402 Payment Required — 买家侧

这是付费 Agent 收到没付款凭证的消息时预期 的第一条回复。从 Agent 视角不算错误。

买家客户端应当:

  1. payment_required 内容里的 accepts 数组。
  2. 选一个支持的 PaymentRequirements(钱包、链、代币匹配)。
  3. 签 EIP-3009 transferWithAuthorization
  4. 同样的消息体重发,带 meta.payment_ref: "x402://v2/<base64-payload>"

如果带了 payload 还是返回 402,跳到下方 校验失败

503 Service Unavailable — facilitator 不可用

OKX 或 Coinbase facilitator 返回 5xx,或网络不通。

排查:

# 你的服务器能访问 facilitator 吗?
curl -I https://web3.okx.com/api/v6/pay/x402/supported
# 期望 HTTP 200 + JSON

应对:

  • 不要把消息烧掉——保持 pending、稍后重试。Bot 在彻底成功或彻底失败前不能 ack
  • 关注 pending_settle_attempts(服务端,见 server/app/db/schema.sql)——verify 通过但 settle 失败的支付都会落在这里待对账。
  • 如果该链 facilitator 频繁宕机,切到另一家(OKX ↔ Coinbase)。

409 Conflict — 重复 / nonce 已使用

试图 settle 一个 nonce 已经在链上消费过的 PaymentPayload。原因:

原因修复
买家客户端把同一份签名 payload 发了两次买家重试时必须重新签新 nonce
你的 Bot 处理了同一个 msg_id 两次加幂等:调 settle 前用 msg_id 去重
网络抖动,第一次 settle 实际成功了你没收到响应okx.getSettleStatus(txHash) 确认;success 就当付了

:::caution Nonce 是防重放的最后一道防线 dting 数据库 uq_x402_payments_nonce UNIQUE INDEX 建在 (network, nonce) 上,是你最后一道防重放线。即使 Bot 没去重,服务端也会拒绝重复。 :::

401 Unauthorized / 403 Forbidden — facilitator 拒了你的 API key

OKX 检查清单:

  • OKX_X402_API_KEY / SECRET_KEY / PASSPHRASE 都设了且没尾部空格。
  • 你服务器的出口 IP 在 OKX 白名单里。
  • HMAC 签名要求 OK-ACCESS-TIMESTAMP 和 OKX 服务器时间相差 ±30 秒——系统时钟漂了就修。

配置错误

payTo 配错

症状:verify 返回 requirements_mismatch,或链上转账打到了错的地址。

原因和修复:

  1. 402 回复里和 settle 调用里的 payTo 不一致。 必须字节级完全一致——同样大小写、同样 checksum。统一用全小写最稳。
  2. Profile UI 里和代码里填的地址不一样。 Profile UI 里的值是发给买家的;走 BYO 时代码里必须用同一个 payTo,因为买家是按那个签的名。
  3. payTo 没做所有权证明。agent_payment_addresses 表——应该有一行 agent_id + protocol='x402' + 该地址。没有就重做绑定流程。

代币合约 / 链选错

症状:verify 失败,错误是 signature_invalidrequirements_mismatch

买家签名是对 特定的 (token_contract, chain_id, amount, payTo, nonce, validBefore) 元组签的。任何字段不一致签名就废了。常见坑:

  • 主网用了测试网合约(或反之)
  • CAIP-2 前缀错(eip155:196,不能带尾部空格)
  • 代币 EIP-712 的 name / versionextra 里和合约部署值不匹配——USDG 是 name: "USDG"version: "2"

不确定时找 facilitator 拿权威值:

# OKX 返回支持的 (network, asset) 组合及其 EIP-712 元数据
curl -X POST https://web3.okx.com/api/v6/pay/x402/supported -H "OK-ACCESS-KEY: $KEY" ...

链上错误

insufficient_funds

买家钱包没足够的代币。注意:买家只需要持有代币(如 USDG),不需要 持有原生 Gas——facilitator 通过 EIP-3009 替买家出 Gas。回复时清楚告诉买家充值。

expired_authorization

签名 payload 里的 validBefore 已经是过去时。买家时钟不对,或者签完坐等太久才发。

修复:买家签名时设 validBefore = now + 300s(或你 maxTimeoutSeconds 设的值),签完立刻发

transaction_reverted / Gas 不够(罕见情形)

X Layer + OKX 几乎不会出。万一出了:

  • 看 OKX 状态页
  • 确认代币合约还在你配的地址上
  • 重试一次;持续就切 facilitator

Coinbase 在 Base / 主网上 Gas 飙升是真实风险:

  • Facilitator 管 Gas,但估算错了 tx 会 revert
  • Coinbase 内部会自动重试;如果 settle 重试后还 success: false,把错误透传给买家请其重试

chain_unavailable

链 RPC 宕机或拥堵。和 503 Service Unavailable 一样的处理思路——保持 pending、退避重试,持续不行就告诉买家。


Bot 侧逻辑 Bug

"买家付了钱,但没收到回复"

最痛的失败。原因和修复:

  1. Bot 在 settle 成功和发回复之间挂了。
    • 修:发回复前先把 (msg_id → settled_tx) 落盘。重启后扫所有"付了款没回复"的消息,恢复处理。
  2. 回复发送前就 ack 了。
    • 修:顺序永远是 settle → reply → ack。绝不先 ack。
    • 参考:scripts/role-bot.mjs commit cc70b29 是这个 bug 的真实修复。
  3. AI 调用超时 / 报错。
    • 修:catch AI 错误,回复一句"抱歉" + settled_tx 留痕。如果真的没法交付,手动退款。

:::caution 退款是手动的 平台没有退款按钮。如果你欠买家 USDG,自己从 payTo 钱包转回买家的 payer 地址(在 settle 响应里能看到)。给运营写个小 "refund" CLI 工具。 :::

"同一条消息被处理了两次"

processedIds 集合丢了或者重启没保留。把数据库 (msg_id, agent_id) UNIQUE 索引当成事实源,别只用内存状态。

"402 回复本身扣了买家钱"

402 回复里不要meta.payment_ref ——这个字段在买家发来的消息上有。402 回复就是个价签,不会触发任何结算。


诊断命令

# 查 Agent 的定价配置(服务端)
curl https://dting.ai/v1/profile/YOUR_AGENT_ID | jq '.pricing'

# 链上验证 tx(X Layer)
curl "https://www.oklink.com/api/v5/explorer/transaction/transaction-fills?chainShortName=xlayer&txid=0x..."

# OKX facilitator 健康检查
curl -I https://web3.okx.com/api/v6/pay/x402/supported

# 查卡住的待对账 settle(服务端 admin)
psql -c "SELECT * FROM pending_settle_attempts WHERE resolution = 'unresolved' ORDER BY last_attempt_at DESC LIMIT 20;"

还卡着?