直接用 error.cause 可获取原始错误,但需手动传入 { cause: originalerror },node.js 16.9+ 和主流浏览器支持;旧环境需降级处理,封装错误时务必传递 cause 并配合 name、stack 定位根因。

直接用 error.cause 就能拿到上一层抛出的原始错误,但前提是它被正确设置了——不是所有错误都有 cause,也不是所有场景都会自动带上。
cause 不是默认存在的
JavaScript 中,只有你主动创建错误时传了 { cause: originalError },新错误才会有 cause 属性。像 throw new Error("xxx") 这样不带选项的写法,error.cause 一定是 undefined。
- Node.js 16.9+ 和主流浏览器(Chrome 93+、Firefox 94+、Safari 15.4+)才支持该特性
- 旧环境需手动降级:把原错误 message 拼进新消息里,或自定义属性如
error.original = e - 第三方库(如 Axios、Zod)部分已适配 cause,但并非全部;调用前建议查文档或实测
逐层回溯原始错误
一个错误可能被多层封装,比如“登录失败” → “API 调用异常” → “网络超时”。要定位最底层那个,就得顺着 cause 往下钻:
- 写个简单工具函数:
function getRootCause(err) {
let e = err;
while (e && e.cause) e = e.cause;
return e;
} - 注意循环终止条件:
e.cause为null或undefined时停止 - 避免无限递归:某些错误可能意外形成环形引用(极少见),可加深度限制(如最多 10 层)
配合 stack 和 name 一起看
单靠 cause 只能知道“谁导致了它”,但不知道“在哪出的问题”。真正排查时,这三个字段常一起用:
-
error.name告诉你错误类型(TypeError、SyntaxError、CustomApiError),比 message 更可靠 -
error.stack显示完整调用路径,包括 cause 链中每一层的堆栈(现代引擎已支持跨 cause 渲染) - 日志记录时建议统一输出:
{ name, message, stack, cause: cause?.name },便于快速筛选和聚合
封装错误时别忘了传 cause
你在做请求封装、状态处理或中间件逻辑时,如果捕获了一个错误又想抛新的,就别只写 throw new Error("处理失败"):
- 正确写法:
throw new Error("用户登录失败", { cause: e }) - 业务层包装技术错误时尤其重要:让前端或监控系统能区分是“密码错误”还是“Redis 连接超时”
- 异步流程中(如
async/await+try/catch),只要没丢弃原错误,就能保持链路完整










