Metadata keys that collide with Object.prototype are silently dropped

当 Langfuse 读取 trace/observation 的 metadata,或 evals 的 LLM-as-judge 模板引用 metadata 时,若 metadata 的 key 恰好撞上 Object.prototype 的成员名(如 toString 、 constructor

快速结论:当 Langfuse 读取 trace/observation 的 metadata,或 evals 的 LLM-as-judge 模板引用 metadata 时,若 metadata 的 key 恰好撞上 Object.prototype 的成员名(如 toString、constructor、__proto__ 等),这些 key 会在读取路径被静默丢弃,报错原文为 Metadata keys that collide with Object.prototype are silently dropped。优先排查 metadata 中是否存在这些特殊 key,并升级到包含 #17686 修复的版本。

适用环境:Issue 已确认工具为 Langfuse;涉及代码路径 packages/shared/src/server/utils/metadata_conversion.ts、normalized-io/parser.ts、features/evals/observationForEval.ts,以及 ingestion 侧的 worker/src/services/IngestionService/utils.ts。Issue 未提供操作系统、Python、CUDA、显卡或依赖版本信息。

最快修复方案:升级到已合并 #17686 修复的 Langfuse 版本(维护者已确认合并并将很快部署)。该 PR 同时修复读取路径与写入路径的问题。

注意事项:Issue 中的 key 写入 ClickHouse 时本身是正确的,问题发生在读出阶段,因此历史数据在旧版本上依旧会被静默丢弃。仅用 Object.prototype.hasOwnProperty.call(acc, name) 只能修复 12 个撞名 key 中的 11 个,__proto__ 仍然会丢失,需要额外用 Object.fromEntries 等方式构造对象。若使用自建构建或未包含该修复的分支,需自行应用补丁。

问题场景

在 Langfuse 中查看 trace 或 observation 时,UI 上该条记录的部分 metadata 不显示;或在使用 evals 的 LLM-as-judge 提示词模板引用 metadata 时,模板取到的值是空的。此时 metadata 已经成功写入 ClickHouse,但在读取路径(metadataArraysToRecord 将并行的 metadata_names / metadata_values 列 zip 成对象)时被丢弃。触发条件是 metadata 的 key 名字恰好是 Object.prototype 上的成员名,例如 toString、constructor、valueOf、hasOwnProperty、isPrototypeOf、propertyIsEnumerable、toLocaleString、__proto__ 等。

报错原文

Metadata keys that collide with Object.prototype are silently dropped

原因分析

确认的原因为:metadataArraysToRecord 用 in 运算符去重,而 in 会沿原型链查找。空累加对象 {} 的原型链上已经有 toString、constructor、valueOf 等成员,因此这些名字被判定为“已存在”,对应值永远不会被写入。受影响的共有 12 个 key 名,即 Object.prototype 上所有能被 in 枚举到的成员。

可能原因(写入侧,属另一个独立缺陷):worker/src/services/IngestionService/utils.ts 中的 convertRecordValuesToString 使用 result[key] = value 在普通对象上赋值。当 key 字面量为 __proto__ 时,会触发 Object.prototype 的 __proto__ 访问器 setter 而不是创建自有属性;由于 value 先被强制转为字符串,该 setter 是规范定义的空操作,不会污染原型,但该 key 会被静默丢弃。其他 11 个原型成员名不受写入侧影响。

环境排查

  • 确认 metadata 中是否存在 toString、constructor、valueOf、hasOwnProperty、isPrototypeOf、propertyIsEnumerable、toLocaleString、__proto__ 等与 Object.prototype 撞名的 key。
  • 确认 Langfuse 版本是否已包含 #17686 的修复。
  • 确认涉及路径:读取侧 metadata_conversion.ts、normalized-io/parser.ts、features/evals/observationForEval.ts;写入侧 worker/src/services/IngestionService/utils.ts。
  • Issue 未确认操作系统、Python、CUDA、PyTorch、显卡或具体依赖版本,无需按这些维度排查。

解决步骤

  1. 升级到已合并 #17686 修复的 Langfuse 版本。维护者已确认该 PR 被合并,并将很快部署。
  2. 若无法立即升级,可参考 #17686 的修复思路自行应用补丁:读取路径不要用 in / 普通对象括号赋值,改用 Object.entries、Object.fromEntries 等不会触碰原型链的方式构造结果对象;写入路径 convertRecordValuesToString 同样避免在普通对象上用 result[key] = value 处理 __proto__ 这类 key。此为按 Issue 证据推断的修改方向,可优先尝试。
  3. 修复后重新触发一次读取,例如重新打开相关 trace/observation 页面,或重跑引用这些 metadata 的 eval。

验证方法

用 Issue 中的复现用例复核:metadataArraysToRecord(["toString"], ["hello"]) 应返回 { toString: "hello" },而不是 {};metadataArraysToRecord(["env", "constructor", "valueOf", "user"], ["prod", "c1", "v1", "bob"]) 应返回包含 constructor: "c1" 与 valueOf: "v1" 的完整对象。在实际环境中,确认 UI 能显示原本被丢弃的 metadata key,且 LLM-as-judge 模板能正确插值这些 key。

参考来源

langfuse/langfuse #17685

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 25351

发表回复

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