[SDK][Python] NaN/Inf floats nested in a pydantic model serialize to invalid JSON (bare NaN/Infinity)

该报错发生在 Langfuse Python SDK 序列化 pydantic 模型时,当模型内嵌的浮点数为 NaN/Inf 时,会绕过安全转换逻辑,直接输出非法的裸 NaN/Infinity JSON 令牌,导致 ingestion 服务器 JSON.parse 拒绝接收。优先检查 langfus

快速结论:该报错发生在 Langfuse Python SDK 序列化 pydantic 模型时,当模型内嵌的浮点数为 NaN/Inf 时,会绕过安全转换逻辑,直接输出非法的裸 NaN/Infinity JSON 令牌,导致 ingestion 服务器 JSON.parse 拒绝接收。优先检查 langfuse/_utils/serializer.py 中 BaseModel 分支是否递归调用了 default()。

适用环境:langfuse-python SDK v4.14.x(当前 main 分支),依赖 pydantic 模型。操作系统、Python 版本、CUDA、显卡等环境变量在 Issue 中未提供,无法确认。

最快修复方案:暂无确认的一步修复方案。可优先尝试将 BaseModel 分支的 return obj.model_dump() 改为 return self.default(obj.model_dump()),让序列化结果递归经过 float 安全转换逻辑。

注意事项:此为 Issue 中提出的修复建议,尚未有官方发布版本验证。修改需自行测试,且 dataclass 分支存在相同问题,建议一并处理。该修改涉及核心链路序列化器,改动后需回归测试正常数据流。

问题场景

在 Langfuse Python SDK 的 tracing 核心路径上,span 的 input/output/metadata 通过 langfuse/_client/attributes.py_serialize 方法序列化。当被追踪的 pydantic 对象中嵌套了 NaN/Inf 浮点数(常见于 ML/评分相关的 payload),就会触发此问题。

报错原文

[SDK][Python] NaN/Inf floats nested in a pydantic model serialize to invalid JSON (bare NaN/Infinity)

原因分析

可能原因是 langfuse/_utils/serializer.py 中的 EventSerializer 对不同类型的对象采用了不同的序列化策略:

  • dict/list 分支会递归调用 self.default(),因此能触发 float 的 NaN/Inf 安全转换(转换为 "NaN""Infinity""-Infinity" 字符串令牌)。
  • pydantic BaseModel 分支直接返回 obj.model_dump(),没有递归回 default(),导致原始 float("nan") 直接进入 Python JSON C-encoder,输出裸的 NaN/Infinity 令牌。
  • dataclass 分支(return asdict(obj))也存在相同问题,未递归处理。

环境排查

  • 确认 langfuse-python SDK 版本为 v4.14.x(Issue 中确认的版本)
  • 检查 pydantic 模型定义,确认字段类型为 float 且可能赋值为 NaN/Inf
  • 确认在使用 span 的 input/output/metadata 参数时传递了包含 NaN/Inf 的 pydantic 对象

解决步骤

  1. 定位 langfuse/_utils/serializer.py,找到 BaseModel 分支(当前行号约 132-139)。
  2. return obj.model_dump() 修改为 return self.default(obj.model_dump()),使序列化结果递归经过 float 安全转换逻辑。
  3. 检查 dataclass 分支(is_dataclass),将 return asdict(obj) 同样修改为 return self.default(asdict(obj)),修复同类问题。
  4. 如果场景中使用了 pydantic 的 raw 属性(嵌套 BaseModel),确保先调用 raw.model_rebuild() 再递归处理。
  5. 修改后运行原有的序列化功能,确认输出为合法 JSON。

验证方法

使用 Issue 中的可运行复现脚本验证:

from pydantic import BaseModel
from langfuse._utils.serializer import EventSerializer

class Scores(BaseModel):
    confidence: float

encoded = EventSerializer().encode(Scores(confidence=float("nan")))
# 修复后应输出 {"confidence": "NaN"} 而非 {"confidence": NaN}
import json
json.loads(encoded, parse_constant=lambda t: (_ for _ in ()).throw(ValueError(t)))
# 修复后不应抛出 ValueError

同时建议在真实 tracing 流程中发送包含 NaN 的 span 数据,确认 ingestion 服务器能正常接收。

参考来源

langfuse/langfuse #16048

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 18903

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注