LibertyNetLibertyNet 开发者

错误字典

每个错误码的成因和解决办法。你不该需要读源码才能从一个错误里恢复。

每个错误都带一个稳定的机器可读 code

json
{ "code": "ID_BINDING_FAILED", "error": "node must use a did:svrp identity" }
警告

code 上分支,永远不要在 error 文本上分支。 code 是契约,不会在没有版本升级的 情况下改变。error 是给人看的,任何版本都可能改措辞。

SDK 的每个错误还带一个直达本页对应条目的 docs 链接。


身份

ID_BINDING_FAILED

HTTP 401。 DID 不是由随附的公钥推导出来的。

成因。 要么这一对确实不匹配,要么——远远更常见——密钥用错了编码解析GET /nodes 发的是 hexGET /peers 发的是 base58。把 base58 当 hex 解析 不会报错,它会产出垃圾,导致每次检查都失败。

解决。 两种编码都接受:

python
key = bytes.fromhex(pk) if re.fullmatch(r"[0-9a-f]{64}", pk) else b58decode(pk)

同时确认你处理了全部三种 DID 形式:8 位 hex 短形式、10 位 hex 碰撞回退、64 位 hex 全形式。 只硬编码 4 字节公式会拒绝合法身份。

注意

如果所有身份突然全都失败,那是编码问题。如果只有一个失败,请认真对待—— 那要么是损坏的记录、要么是伪造,应该报告而不是跳过。


BAD_SIGNATURE

HTTP 401。 签名在规范字节上验证不通过。

成因。 几乎总是规范化漂移,而不是密钥坏了。注册表会用你发来的字段重建被签名的 字节,然后对着重建的那份验证。你的序列化只要差一个字节就会失败,而一切看起来都很正常。

常见元凶:

  • 布尔值序列化成 true/false,而不是 Python 的 True/False
  • 字段顺序按你的 JSON 库来,而不是按规范化器来
  • 列表字段拼接前没有排序
  • 时间戳带了时区偏移而不是 Z,或者带了毫秒

解决。 不要从文字描述里重新推导规范化。用已经过审计的实现: operator-console/lib/crypto/canonical.tssvrp_crypto.py、或 ln-node bind

这正是 SDK 拒绝重新实现签名步骤的原因。


会话

NO_SESSION · SESSION_EXPIRED

HTTP 401。 没有 bearer 头,或者会话超过了一小时。

解决。 重新登录。会话故意做得短且不可续期——永不过期的令牌是值得偷的令牌。 捕获这个错误然后重新认证,不要试图延长它。

SDK 在发请求之前就抛 NO_SESSION,所以你在调用处就能拿到它,而不是等一个来回之后。


BAD_CHALLENGE

HTTP 401。 登录挑战未知、过期或已被使用。

成因。 挑战活 300 秒,且首次使用即消耗。不能重放,也不能拿着它等用户去泡杯咖啡。

解决。 在签名前立即取新挑战。永远不要缓存。


绑定

NOT_FOUND(resolve 时)

HTTP 404。 绑定码无效、过期或已被使用。

注意

这个歧义是故意的。 三种成因返回完全相同的响应。

如果它们可区分,这个端点就成了"测试某个码是否真实存在"的预言机。所以错的码和过期的码 看起来一模一样。更差的错误信息,是换取这个端点不可枚举的代价。


RATE_LIMITED

HTTP 429。 600 秒内对同一个码失败 5 次。

解决。 等窗口过去,然后用新码。成功的 resolve 会清零计数器。如果你合理地撞上了这个, 多半是在重试一个打错的码——让用户重新读一遍,而不是重试。


TTL_TOO_LONG · ALREADY_EXPIRED · BAD_STATE

HTTP 400 / 409。

Code含义解决
TTL_TOO_LONG会话窗口超过 600 秒或 ≤ 0用 RFC3339 UTC(Z 后缀、秒精度),窗口保持在 10 分钟内
ALREADY_EXPIREDexpires_at 已是过去检查机器时钟——偏差几秒就会让本地看起来正确的时间戳在远端被拒
BAD_STATE会话已处于终态终态永不改变。开一个新会话,不要试图复活它

STALE_TS

HTTP 401。 节点的轮询时间戳与注册表时间相差超过 300 秒。

解决。 修节点的时钟。 用 NTP。这是一个伪装成认证问题的时钟问题,重试多少次都没用。


仅 SDK

NOT_YET_WIRED

你调用了一个没有数据源、或者根本没建好的东西。

这不是 bug。 另一种做法——返回一个看起来合理的零——会让一个未接通的余额被当成收益 展示给用户。

解决。error.level

level含义怎么做
not_yet_wired端点在线,无数据源*Raw() 读法,并把说明和数值一起展示
testing代码存在且测试通过,未部署等。关注状态页
planned没做现在不要围绕它做设计

TRANSPORT_ERROR

网络调用本身失败——DNS、TLS、超时、离线。

SDK 已经对瞬时失败(429、5xx、网络错误)做了指数退避加抖动的重试, 并且绝不重试 4xx——重放一个被拒的签名,只会更贵地被再拒一次。


这里没有你遇到的错误?

来问

遇到本页没有记录的错误码,那就是文档 bug,我们想知道。请带上 code 和你当时在调什么。