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 检查):

const parsed = schema.safeParse(request.item);
if (!parsed.success) {
    const issues = parsed.error.issues.map((i) => ({
        path: i.path.join('.'),
        message: i.message,
        code: i.code,
    }));
    const summary = issues.slice(0, 3).map((i) => `${i.path || '(root)'}: ${i.message}`).join('; ');
    ...
    (err as any).code = 'INVALID_METADATA';
    (err as any).status = 422;
    (err as any).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