DEBUG.WIKI
阿里云;从建站到云上业务;云服务器 · 数据库 · 对象存储;查看产品 →
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

Fastify error.statusCode 写成 600 后进程异常退出

Fastify 错误对象带 statusCode 600 或更大值,启用 tracing 时可能在拒绝回调中再次抛错。对照 5.12.7 状态检查路径,在业务错误进入框架前映射合法 HTTP 状态。

异步路由抛出的错误带有 statusCode: 600,启用诊断订阅后,请求没有得到预期的 500,反而出现 FST_ERR_BAD_STATUS_CODE 或未处理拒绝。Fastify 5.12.5、5.12.7 的这条路径需要检查错误对象上的 HTTP 状态值。

setErrorStatusCode 只判断错误状态是否大于等于 400,再把它交给 reply.code;reply.code 却只接受 100 到 599。诊断 tracing 开启时,这个设置发生在发布 handler error 事件之前,也早于后面的正常错误发送捕获,非法值便可能从 Promise 拒绝回调逃逸。

在抛入框架前规范业务错误状态

不要把内部业务编号、上游自定义数值或任意外部字段直接写成 HTTP statusCode。应用自己创建的错误应映射到明确允许的 4xx 或 5xx。对于已有第三方业务错误,可在拥有转换权的路由调用边界包装,例如:

function asHttpError(error) {
  const candidate = error?.statusCode ?? error?.status;
  const statusCode = Number.isInteger(candidate)
    && candidate >= 400 && candidate <= 599
    ? candidate
    : 500;
  const wrapped = new Error('请求处理失败', { cause: error });
  wrapped.statusCode = statusCode;
  return wrapped;
}

在既有异步业务调用的 catch 中抛出这个包装错误,再交给 Fastify。示例使用支持 Error cause 的 Node 环境;日志与错误响应继续经过项目原有规则,不向客户端展开内部 cause。业务若只允许少数状态码,应使用更窄的明确映射。

这不是让所有错误都改成 500,也不接受字符串 '404' 自动变成数字。应用已经有类型化业务错误时,优先按其类型选择状态,保留原来的权限与校验失败分类。

全局 error handler 可能已经太晚

如果错误在 tracing 的拒绝处理前段就因非法状态再次抛出,单独在 setErrorHandler 里兜底,并不覆盖这次调用。应先修正产生或转交错误的边界,不能因为加了一个统一 handler 就假定它一定执行过。

另一个默认错误头处理分支也只检查下界;更大的非法值可能走到 Node 的响应头写入错误。没有诊断订阅时,症状可以不同,因此不要将“关闭 tracing 后这次没退出”写成根因消失,更不应关闭可观测性作为长期处理。

正常 HTTP 状态范围与业务错误编号是两项数据。需要保留内部编号时,放在既有业务字段或受控日志中,不借用 statusCode。

验收覆盖有效 400、500、599,以及 600、1000、非整数和缺失状态;分别检查原来的诊断开启与关闭条件。应看到合法响应、预期错误分类及后续请求仍能处理,不能只确认进程没有退出。截至 2026 年 10 月 26 日,正式 5.12.7 仍有上述状态检查边界,未发布的回退修改不能当作已安装修复。