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 仍有上述状态检查边界,未发布的回退修改不能当作已安装修复。


