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

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions