Skip to content

元数据保存的 422 也丢掉 union 分支处方:一个 view 保存失败只回一条 path:"" message:"Invalid input",Studio 无字段可高亮 #5364

Description

@os-zhuang

在做 #5014(REST zodIssuesToFields 展开 invalid_union,PR #5362)时顺手核出的第四个消费者,不在那单的文件面内,故独立记录,未在该 PR 中修改

落点

packages/metadata-protocol/src/protocol.ts:7128saveMetaItem 的 spec-conformance 检查):

constparsed=schema.safeParse(request.item);if(!parsed.success){constissues=parsed.error.issues.map((i)=>({path: i.path.join('.'),message: i.message,code: i.code,}));constsummary=issues.slice(0,3).map((i)=>`${i.path||'(root)'}: ${i.message}`).join('; ');
...
(errasany).code='INVALID_METADATA';(errasany).status=422;(errasany).issues=issues;

(源码里 '(root)' 那处实际写的是尖括号包住 root 的字面量。)

#5014 一样:只映射顶层 issue,issue.errors 里每个分支的真实拒绝理由(含 #4001 那批 strictObject 的策展处方)在 .map() 处被丢弃。差别在于这条路径才是 spec 里那些处方真正的归宿——view / dashboard / flow 这些 overlay 类型走的就是它,而 REST 的 zodIssuesToFields 只服务数据路由的 ingress schema。

实测(origin/main @ 553a47fda,用 getMetadataTypeSchema('view'),即该函数 resolveOverlaySchema 用的同一个 schema)

输入一个 list view,columns[0].summary 写了未知键:

{ name:'task_list', object:'task', type:'list', label:'Tasks',
columns: [{ field:'title', summary: { type:'sum', fieldd:'amount' } }] }

客户端/Studio 拿到的 issues 全文:

[ { "path": "", "message": "Invalid input", "code": "invalid_union" } ]

422 的 message 摘要行:root: Invalid input(root 外面是尖括号)。

而被丢掉的分支里躺着的是:

branch[1] unrecognized_keys [] Unrecognized key(s) on this view container: `type`, `columns`. Until #4001 closed these shapes …
branch[2] invalid_value ["type"] Invalid option: expected one of "grid"|"kanban"|"gallery"|…
branch[3] invalid_value ["type"] Invalid option: expected one of "simple"|"tabbed"|"wizard"|…

即:一个字段名都没有到达作者,path 是空串,Studio 表单没有任何东西可以高亮——注释里写的「so the Studio form can highlight the offending field」在顶层是 union 的类型上不成立。ViewSchema 顶层本身是 union(view.zod.ts:2332z.preprocess(stripViewConsoleDecorations, z.union([...]))),所以 view 类型的每一次保存失败都退化成这一条。

与已有单的关系

同一缺陷的四个消费者,判定必须一致(否则同一个错误在终端/API/Studio 说法不同):

建议修法与前三处一致:照抄 #4971selectUnionBranches 策略(丢弃只报根部 KIND 不匹配的分支;报得最少的分支胜出——这条是防止一个未知键被 N 个分支各报一遍;unrecognized_keys 破平局;并列全出且有上限;嵌套 union 按绝对路径递归)。注意 issues[] 的条数会变,属 wire 可见改动;这条路径不走 ADR-0114 的 fields[] 目录(它透传 zod 原始 code),是否顺手对齐目录需要单独裁决。

未打标签,留给 PM 分诊。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions