name: root-cause-tracing description: 系统性地通过调用栈回溯追踪错误以找到原始触发器。当错误在执行深处发生时,并且您需要回溯以找到原始触发器时使用。 version: 1.1.0
根本原因追踪
概述
错误经常在调用栈深处显现(例如 git init 在错误目录、文件创建在错误位置、数据库以错误路径打开)。您的本能是在错误出现的地方修复,但这只是治标。
核心原则: 通过调用链回溯,直到找到原始触发器,然后在源头上修复。
何时使用
使用时机:
- 错误发生在执行深处(非入口点)
- 堆栈跟踪显示长调用链
- 不清楚无效数据源自何处
- 需要找到触发问题的测试/代码
追踪过程
1. 观察症状
Error: git init failed in ~/project/packages/core
2. 找到直接原因
什么代码直接导致此错误?
await execFileAsync('git', ['init'], { cwd: projectDir });
3. 询问:什么调用了此代码?
WorktreeManager.createSessionWorktree(projectDir, sessionId)
→ called by Session.initializeWorkspace()
→ called by Session.create()
→ called by test at Project.create()
4. 持续向上追踪
传递了什么值?
projectDir = ''(空字符串!)- 空字符串作为
cwd解析为process.cwd() - 那是源代码目录!
5. 找到原始触发器
空字符串来自哪里?
const context = setupCoreTest(); // Returns { tempDir: '' }
Project.create('name', context.tempDir); // Accessed before beforeEach!
添加堆栈跟踪
当无法手动追踪时,添加检测:
// 在有问题的操作之前
async function gitInit(directory: string) {
const stack = new Error().stack;
console.error('DEBUG git init:', {
directory,
cwd: process.cwd(),
nodeEnv: process.env.NODE_ENV,
stack,
});
await execFileAsync('git', ['init'], { cwd: directory });
}
关键: 在测试中使用 console.error()(而不是 logger - 可能不显示)
运行并捕获:
bun test 2>&1 | grep 'DEBUG git init'
分析堆栈跟踪:
- 查找测试文件名称
- 找到触发调用的行号
- 识别模式(相同测试?相同参数?)
找到导致污染的测试
如果某些东西在测试期间出现,但不知道是哪个测试:
使用二分脚本逐个运行测试:
# 示例:找到哪个测试在错误位置创建 .git
bun test --run --bail 2>&1 | tee test-output.log
逐个运行测试,在第一个污染者处停止。
真实示例:空 projectDir
症状: .git 创建在 packages/core/(源代码)
追踪链:
git init在process.cwd()中运行 ← 空的 cwd 参数- WorktreeManager 以空 projectDir 调用
- Session.create() 传递空字符串
- 测试在 beforeEach 之前访问
context.tempDir - setupCoreTest() 最初返回
{ tempDir: '' }
根本原因: 顶级变量初始化访问空值
修复: 使 tempDir 成为 getter,如果在 beforeEach 之前访问则抛出异常
还添加了深度防御:
- 第1层:Project.create() 验证目录
- 第2层:WorkspaceManager 验证非空
- 第3层:NODE_ENV 保护拒绝在 tmpdir 外 git init
- 第4层:在 git init 之前记录堆栈跟踪
关键原则
永远不要只在错误出现的地方修复。 回溯以找到原始触发器。
堆栈跟踪技巧
在测试中: 使用 console.error() 而不是 logger - logger 可能被抑制
在操作之前: 在危险操作之前记录,而不是在失败之后
包括上下文: 目录、cwd、环境变量、时间戳
捕获堆栈: new Error().stack 显示完整调用链
现实世界影响
从调试会话中:
- 通过5级追踪找到根本原因
- 在源头上修复(getter 验证)
- 添加了4层防御
- 1847个测试通过,零污染