其他
当错误出现在调用栈深处且来源不明时…
适用于 bug 在执行深处暴露、堆栈很长或无效数据来源不明时,通过沿调用链向上回溯找到原始触发点,从源头修复并加防御。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
当错误出现在调用栈深处且来源不明时,回溯通用
解决思路
- 先观察症状:明确错误表现和位置,例如 `Error: git init failed in /Users/jesse/project/packages/core`。
- 定位直接原因:找出直接导致该错误的代码,例如 `await execFileAsync('git', ['init'], { cwd: projectDir });`。
- 追问「谁调用了它」:沿调用链向上查,例如 `WorktreeManager.createSessionWorktree(...)` → `Session.initializeWorkspace()` → `Session.create()` → 测试中的 `Project.create()`。
- 继续向上回溯并检查上游传入的值:确认调用者传了什么,例如 `projectDir = ''`(空字符串)。
- 理解值的语义和解析行为:空字符串作为 `cwd` 会解析为 `process.cwd()`,也就是源代码目录。
- 找到原始触发点:定位空字符串从哪来,例如 `const context = setupCoreTest();` 初始返回 `{ tempDir: '' }`,而 `Project.create('name', context.tempDir);` 在 `beforeEach` 之前访问了它。
- 判断是否已到源头:如果能再向上回溯一层就继续;只有找到原始触发点才停。
- 在源头修复:不要只修错误出现的位置;修原始触发点,例如把 `tempDir` 改成 getter,在 `beforeEach` 之前访问时抛错。
- 增加纵深防御:在每一层加校验或保护,例如 Layer 1 `Project.create()` 校验 directory;Layer 2 `WorkspaceManager` 校验非空;Layer 3 `NODE_ENV` guard 拒绝在 tmpdir 之外执行 git init;Layer 4 在 git init 前记录 stack trace。
- 手动追踪困难时,在问题操作前加 instrumentation:在危险操作之前记录调试信息,不要等失败后再记录。
- 使用 `new Error().stack` 捕获完整调用链,并记录 `directory`、`cwd`、`process.env.NODE_ENV`、时间戳等上下文。
- 在测试中使用 `console.error()` 输出调试信息,不要用 logger,因为 logger 可能被抑制不显示。
- 运行测试并捕获调试输出,例如 `npm test 2>&1 | grep 'DEBUG git init'`。
- 分析 stack traces:查找测试文件名、触发调用的行号,以及模式(相同测试?相同参数?)。
- 如果测试期间出现污染但不知道是哪个测试造成,使用二分脚本 `@find-polluter.sh`。
- 运行隔离脚本逐条执行测试,例如 `./find-polluter.sh '.git' 'src/**/*.test.ts'`,在第一个造成污染的测试处停止;用法见脚本说明。
- 复盘真实示例的追溯链:`git init` 在 `process.cwd()` 中运行(cwd 参数为空)→ `WorktreeManager` 收到空 `projectDir` → `Session.create()` 传入空字符串 → 测试在 `beforeEach` 前访问 `context.tempDir` → `setupCoreTest()` 初始返回 `{ tempDir: '' }`。
- 从示例中确认根因类型:顶层变量初始化时访问了空值。
- 应用修复并验证:把 `tempDir` 改为 getter,提前访问时抛错;再加入多层防御,使 bug 不可能发生。
- 验证结果:运行测试,例如 1847 tests passed, zero pollution。
- 绝不要只修错误出现的位置;必须回溯找到原始触发点,并在源头修复。
适用边界 · 注意事项
- 错误发生在入口点且没有更深调用链可回溯时,不需要使用此回溯流程。
- 调用链无法继续向上回溯、已经到死路时,不要在本方法上死磕,可先在症状点处理。