DEBUG.WIKI
丽萨主机;为跨境业务选好 IP;原生 / 住宅 IP · 按套餐选择;查看 IP →
晚安云;香港 CN2 ¥15/月
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →

msgspec 把超大整数转 float,为什么抛出 SystemError

msgspec 0.21.1 的 convert 在整数超出 double 范围时遗漏异常处理。正式 0.22.0 改为 ValidationError;嵌套字段同样要验收,Meta 约束构造属于另一条路径。

Python 的任意精度整数本身合法,转成 float 却可能超出双精度范围。msgspec 0.21.1 对这一情况调用 convert 时,可能没有给出预期的 ValidationError,而是抛出:

SystemError: <built-in function convert> returned a result with an exception set

例如输入 10**400,目标类型是 float。如果外层只捕获 msgspec.ValidationError,这次错误就会漏到服务的内部异常分支。把 strict 改成 False 也不能让这个数放进有限的双精度浮点数。

超范围输入触发了错误的 C 返回路径

0.21.1 的整数转浮点路径直接把 PyLong_AsDouble() 的结果交给下一步,没有先检查这次转换是否设置了异常。整数太大时,底层已经设置 OverflowError,但函数仍继续返回对象,最终由解释器报告 SystemError。

同版本的 JSON 浮点解码路径会给出 ValidationError: Number out of range,所以“先在另一个入口试过能正确拒绝”不能证明 convert 也有相同行为。裸 float 和嵌套字段都可能走到这次整数转换。

0.22.0 已修正 convert 的错误出口

msgspec 0.22.0 的正式实现会检查 PyLong_AsDouble() 返回后的异常状态,将该输入转成带路径的 Number out of range 验证错误。按现有依赖管理方式选择兼容的已发布版本并更新锁文件;0.22.0 要求 Python 3.10 或更高。

下面是需要验证的入口示意,超范围值仍应被拒绝,不是升级后自动得到某个可用浮点值:

import msgspec

try:
    msgspec.convert({"value": 10**400}, dict[str, float])
except msgspec.ValidationError as exc:
    error_text = str(exc)

检查错误仍能定位到 value,并核对上层返回的状态码与错误结构。不能通过捕获 SystemError 后返回 0、无穷大或成功响应来代替非法输入处理。

如果短期无法升级,可以在这个已明确为整数转浮点的输入边界先做范围检查。仅对业务允许的整数调用 float(value),捕获其 OverflowError 后转成项目原有的参数错误;还需拒绝不允许的类型,并继续原来的模型校验。不要在整个请求外层把任意 SystemError 都解释成用户输错数值,那会掩盖其他内部故障。

不把 convert 修复扩展到 Meta 构造

msgspec.Meta(gt=...) 等约束对象的构造走另一套检查。0.22.0 的 convert 修复不代表给 Meta 传入 10**400 这样的约束值也已获得相同保护。应按实际浮点字段的数值范围设计约束,避免将无法表示的整数当作浮点边界。

如果业务必须保留任意精度整数,就使用整数目标;如果需要精确十进制,再按协议选择 Decimal 等适合的类型。浮点转换成功也可能损失精度,不能把“不再抛 SystemError”当作精确数值已经得到保证。

验收包括正常整数、正负超范围整数、裸 float 目标和真实嵌套模型,检查旧错误出口是否回到预期验证流程。保留 JSON 解码入口的对应测试,避免修正一种输入后,又把其他入口的错误处理改坏。