Skip to content

console: System Hub 计数的 .catch(() => ({ data: [] })) 把 500 / 401 / 403 / 断网都渲染成一个确定的 0(404 根本到不了它) #3679

Description

@yinlianghui

越界发现,记录于 #3670(把 Organizations 计数改查真对象名 sys_organization)期间,为写「修前后行为矩阵」而实测 .catch 到底吞了什么。按纪律只报不改,单独立单,未认领,留给 PM 分诊。

基线:origin/main @ 0fcd57199;框架侧 ../objectstack @ b4872a868

事实(与 #3670 正文的一处订正)

apps/console/src/pages/system/SystemHubPage.tsxfetchCounts 给五个 find 各挂了一个 .catch(() => ({ data: [] }))#3670 正文把「对象不存在 → 404 被静默吞掉 → 计数恒 0」归因给这个 .catch实测这条归因是错的,但结论不变:

  • 对象不存在时,后端答 404 + code: 'OBJECT_NOT_FOUND'(packages/rest/src/rest-server.tsOBJECT_NOT_FOUND 分支),而 ObjectStackAdapter.find() 自己就把它吃掉了 —— packages/data-objectstack/src/index.tsis404Error(err) 命中后把资源记进 missingResourcesreturn { data: [], total: 0 },后续同名调用直接短路。这是有意设计(注释原话:callers treat empty data as "feature unavailable"),给的是 resolve 不是 reject。
  • 所以 404 从来没有到达页面这一层的 .catch。计数恒 0 是适配器的正常契约行为,.catch 在那条路径上是空转。

那么这个 .catch 实际覆盖的是另一类:适配器对非 404 一律 throw。于是

后端实际发生的事 适配器 页面 .catch 屏幕
对象不存在(404 OBJECT_NOT_FOUND) 吃掉,resolve 空 未触发 0
对象存在但确实没有记录 resolve 空 未触发 0
500 / 401 / 403 / 断网 / 超时 rethrow 吃掉 0

三种语义完全不同的情况给出同一个像素,且第三行没有任何错误提示、没有重试、没有 null 回退 —— 屏幕上是一个看起来很确定的数字。最容易复现的一条不是后端宕机(那时整个 console 都进不去),而是单个对象上的权限拒绝:一个能进 System Hub 但对 sys_audit_log 没有读权限的管理员,看到的是「Audit Log 0 entries」,而不是「你没有权限」。

顺带一条同源的:fetchCounts 外层还有一个 try { … } catch { /* Keep nulls on failure */ }。因为每个 promise 都自带 .catch,Promise.all 已经不可能 reject,这个外层 catch 只在 dataSource.find 同步抛出时才可能进入 —— 也就是说「保留 null(不显示徽章)」这条本意的降级路径实际上是死的,而它恰好是唯一能把「不知道」与「0」区分开的形态。

为什么单独立单

可能的修法方向(留给分诊,不预判)

  1. 把每个 .catch 的返回值从「空数组」换成一个可辨的失败标记,让对应卡片的 count 落回 null(徽章本来就有 count !== null 的分支,即「不显示」),必要时补一句错误文案。代价:要区分「适配器给的空」和「失败」,而前者本身也可能是 404。
  2. 连同 SystemHubPage 一起退场 —— 该文件 docblock 已标 @deprecated(「superseded by the metadata-driven left-side menu」),这也是 console: 系统导航 / System Hub 的 users / organizations / roles / positions / permissions 五个入口没有对应路由 —— 两个落 "Page not found",三个跳进不存在对象 system 的记录页 #3655 裁决里的选项 C。若走这条,本单随之作废。
  3. 更上游:让计数走一个真正的 count 端点(文件里已有 // TODO: Replace with count-specific API endpoint when available),顺带重做失败语义。

严重度我判断不准,按纪律照实立单不自行压低:发生频率取决于部署里非 404 失败有多常见,而后果是一个看起来正常的错误数字。

已就关键词(fetchCountsSystemHubPagecatchmissingResourcesis404ErrorOBJECT_NOT_FOUND、静默/吞)搜过本仓开放 issue 与 PR,无同源单(#3670 是对象名,#3672 是孤儿页面)。


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions