关于 error-debugging
error-debugging 是面向开发者的错误诊断技能,可从崩溃报告、堆栈跟踪和日志中定位根因并提出修复与验证步骤。它强调先识别平台、必要时符号化,再以代码和证据核实假设。
主要功能
- 01跨平台错误分析
- 02识别并定位失败帧
- 03混淆堆栈符号化
- 04追溯并验证根因
- 05提出修复并运行验证
适用场景
- 01解释崩溃报告或错误日志
- 02诊断测试、构建或运行时失败
- 03分析发布版混淆堆栈
- 04按请求修复并验证错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jablonkai/ skills --skill error-debugging安装后在 Claude Code 中输入/error-debugging确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/flutter-dart.mdkotlin-android-kmp.mdother-languages.mdrust-cpp.mdswift-apple.mdsymbolication.mdworked-examples.md详细介绍
错误调试
目的
将错误消息转化为解释和修复方案。输入可以是用户手头的任何内容——堆栈跟踪、崩溃报告、panic、日志摘录,有时只有一段截图描述。输出包括:实际失败的代码行、失败原因、需要修改的内容,以及如何确认修改有效。
大部分价值都在中间这一步。抛出异常的栈帧很少就是出错的栈帧——渲染例程中的 NullPointerException 通常意味着上游代码传入了一个本不该为空的值。报告原因,而不是症状。
适用场景
- 用户粘贴了堆栈跟踪、崩溃报告、panic、ANR 或错误日志——无论是否附带问题
- 用户询问错误的含义、应用崩溃的原因,或故障的来源
- 发布版本的跟踪信息需要反混淆或符号化后才能读取
- 测试失败、构建失败或运行时日志需要进行根因分析
不适用于此技能:
- 没有具体故障,需要排查整个项目的问题 →
code-analyzer - 尚未获取失败运行记录的 GitHub Actions 运行 →
github-fix-ci-error(该技能会获取运行记录;如果其日志需要深入分析跟踪信息,再回到这里)
前提条件
开始分析前,先确定两件事。
1. 这由哪个平台生成? 根据跟踪信息的特征判断,而不是根据用户的描述——描述经常不准确,也可能缺失:
| 跟踪信息中的特征 | 平台 | 参考资料 |
|---|---|---|
at com.foo.Bar.baz(Bar.kt:42)、Caused by:、FATAL EXCEPTION | Kotlin / Java / Android | kotlin-android-kmp.md |
ANR in、Input dispatching timed out、"main" prio=5 tid=1 线程转储 | Android ANR | kotlin-android-kmp.md |
kfun:、Uncaught Kotlin exception、kotlin.Throwable、ObjCException | Kotlin/Native(iOS 上的 KMP) | kotlin-android-kmp.md |
androidx.compose.*、Snapshot、“recomposition”、Composer 栈帧 | Compose / CMP | kotlin-android-kmp.md |
FlutterError、RenderFlex、package:flutter/src/...、<asynchronous suspension> | Flutter / Dart | flutter-dart.md |
Exception Type: EXC_BAD_ACCESS、Thread 0 Crashed:、.ips、libswiftCore.dylib | Swift / Apple | swift-apple.md |
thread 'main' panicked at、note: run with RUST_BACKTRACE=1、core::panicking | Rust | rust-cpp.md |
SIGSEGV、AddressSanitizer:、#0 0x...、ndk-stack、核心转储 | C / C++ / NDK | rust-cpp.md |
Traceback (most recent call last)、at Object.<anonymous>、goroutine 1 [running] | Python / JS / Go | other-languages.md |
加载与平台匹配的那份参考资料。全部加载会浪费上下文,还会混入不适用的惯用做法。例外情况是跟踪信息跨越平台边界——例如,Kotlin/Native 异常导致 iOS 应用终止、携带原生跟踪信息的 Flutter PlatformException,或 JNI 崩溃——此时也需要加载另一侧的参考资料。
2. 跟踪信息是否可读,还是需要先进行符号化?
十六进制地址、单字母类名(a.b.c)、<optimized out> 或缺少行号,都意味着跟踪信息已混淆或尚未符号化。直接分析会得出看似肯定、实则荒谬的结论。请先进行符号化——有关 R8 映射文件、dSYM、flutter symbolize、ndk-stack 和 addr2line,请参阅 symbolication.md。
如果缺少所需的制品(映射文件、dSYM、调试版本),请明确说明,提取仍然有效的信息(异常类型、线程状态、顶层模块),并告知用户需要提供哪些内容,才能进行真正的诊断。
工作流
步骤 1:获取完整错误信息
获取完整的调用栈,而不只是前 3 行。具体请确保包含:
- 异常类型和消息原文
- 完整的栈帧列表,包括每个
Caused by:/suppressed/ 嵌套链 - 出错时所在的线程(主线程/UI 线程上的故障与后台线程上的故障,成因不同)
- 上下文:调试版还是发布版构建、设备/OS、问题是可复现还是偶发、何时开始出现
如果用户粘贴的调用栈被截断,请索取其余部分——关键栈帧通常就在中间部分。如果错误记录在文件中,请直接读取文件,而不是让用户粘贴:
# Keep log reading cheap — grep for the failure region instead of loading whole files
grep -n -A 40 -iE 'exception|fatal|panic|error|traceback' <logfile> | head -120
对于 Android,请直接提取调用栈:
adb logcat -d -b crash | tail -100
步骤 2:按需进行符号化或反混淆
仅当「先决条件 2」指出需要时才进行。请参阅 symbolication.md。 不要跳过这一步,直接分析无法阅读的调用栈——根据混淆后的栈帧得出的每个结论,都只是伪装成答案的猜测。
步骤 3:定位出错的栈帧
不同平台的栈帧顺序各不相同:JVM、Swift、Rust、Go、JS 和原生调用栈会将抛出异常的栈帧列在最前面;Python 则列在最后面。先确认顺序,再回答:
- 异常在哪里抛出? 找出最接近抛出位置、且属于用户自身代码的栈帧,而不是紧挨着它的框架栈帧。框架栈帧说明了机制;你自己的栈帧说明了错误所在。
- 最深层的
Caused by:是什么? 在异常链中,最后一个原因通常才是真正原因;外层包装异常只是传递异常。 - 哪些栈帧属于该项目? 根据应用的包/模块前缀筛选,其余内容都只是上下文。
然后打开该行的实际源代码。只要能查看代码,就绝不要只根据调用栈进行诊断:
# read the failing site plus the surrounding context
grep -n "<symbol>" -r <src-dir>
如果有 Serena、LSP 等支持符号的工具,请用它们查看所在函数及其调用方,而不是通读整个文件。
如果无法获取源代码(例如来自第三方应用的调用栈,或没有代码仓库的代码片段),请一开始就说明这一点,并将所有依赖未查看代码的结论标记为可能或推测。
步骤 4:追溯根本原因
从出错行反向追查,找出错误状态的来源。对于每个候选原因,你都必须能指出导致故障的具体值或条件。
无论平台是什么,都要考虑以下跨领域原因:
- 空值/缺失值——可选值被强制解包、可空值被解引用、假设映射查询一定有结果
- 生命周期/销毁后使用——对象被捕获时有效,但使用时已无效
- 并发——竞态、撕裂读取、未同步的修改、死锁、在错误线程上执行工作
- 违反约定——API 调用顺序错误、状态不符,或未在要求的线程/执行者上调用
- 资源耗尽——OOM、文件描述符耗尽、缓存或集合无界增长
- 边界不匹配——序列化、FFI、平台通道、JNI:两侧的数据形态不同
平台特定的问题模式目录(被吞掉的 CancellationException、构建期间调用 setState、主执行者违规、RefCell 重复借用、释放后使用等)位于先决条件中加载的平台参考资料。
请区分以下两者,并明确指出属于哪一种:
- 直接原因——抛出异常的操作(对只有 2 个元素的列表访问
list[3]) - 根本原因——状态出错的原因(API 返回的项目数少于调用方的假设,且没有任何校验)
仅在直接原因处修复,通常只是转移错误,而不是真正修复。若你将此类修复作为权宜之计提出,请明确说明。
第 5 步:修复前验证假设
将假设表述为可证伪的结论,然后进行测试。先从成本最低的测试开始:
- 带着假设重新阅读代码路径——跟踪中的每一帧都符合吗?
- 检查同一区域的近期历史记录:
git log -p -L <start>,<end>:<file> | head -80,或git log --oneline -- <file> - 在疑似起因处添加临时断言或日志,然后重现问题
- 编写一个能重现崩溃的失败测试——这是最佳结果,因为修复后它可以作为回归防护
如果跟踪内容不能完全符合假设,那么假设就是错的。请明确说明并继续调查, 不要据此提交一个看似合理的解释。
第 6 步:提出修复方案
按以下格式简明、有序、易于浏览地给出分析:
## What failed
<exception type + the failing line, as `path/to/File.kt:42`>
## Why
<root cause in 2–4 sentences: the bad state, where it came from, why it reached this line>
## Evidence
<the specific frames / code / history that support this, with file:line references>
## Fix
<the concrete change; a code sketch only when prose is not enough>
## Verify
<the command, test, or reproduction step that proves it — e.g. `./gradlew :app:testDebugUnitTest --tests '*FooTest*'`>
## Also worth checking
<other call sites with the same flaw, or the guard that would have caught this earlier — omit if none>
用户要求修复时再应用修复。如果用户只问错误是什么意思,则在分析后停止——不要开始编辑代码。
第 7 步:验证修复结果
应用修复后,运行项目自己的验证流程(测试、构建、分析器),并报告实际结果——包括验证仍然失败的情况。未经运行验证的修复只是提议,不算修复。
如果同类错误可能也出现在其他地方,请用一行提及。不要扩展为对周边模块的重构。
操作模式
此技能支持三种模式;根据用户的请求选择:
| 操作 | 用户意图 | 输出 |
|---|---|---|
explain-error | “这是什么意思?” | 步骤 1–4,用通俗语言解释,不修改代码 |
analyze(默认) | “为什么会崩溃”,或只粘贴跟踪信息 | 步骤 1–6,提供完整报告和建议的修复方案 |
fix | “修复这个”“javítsd” | 步骤 1–7,应用更改并验证 |
关键约束
- 绝不编造帧、行号或文件路径。 如果跟踪被截断或混淆,请说明缺少什么,不要自行补全。
- 分析任何发布版或混淆后的跟踪前,先进行符号化。 未符号化的诊断只是猜测。
- 代码可用时,务必阅读失败行上的实际源码。 仅在无法获取代码时,才根据跟踪本身进行分析。
- 区分确定程度。 将每条结论标记为已确认(可指出对应代码行)、较可能(符合证据,但未经验证)或推测(需要更多数据)。不要把第三种说成第一种。
- 每份报告只分析一个根因。 如果跟踪显示多个相互独立的故障,应分别分析,不要混在一起。
- 不要把原始日志贴回给用户。 只引用能够说明诊断依据的少数几行。
- 不要擅自扩大范围。 只修复用户询问的崩溃;列出相关问题,但不要重构。
- 绝不要将崩溃日志、
.ips文件或映射文件发送到外部服务。 这些文件通常包含设备标识符、用户路径和内部符号名称。
参考资料
- symbolication.md — 各平台的反混淆和符号化;分析发布版前先完成此步骤
- kotlin-android-kmp.md — Kotlin/JVM、Android、协程、ANR、Kotlin/Native、Compose 和 CMP
- flutter-dart.md — FlutterError、渲染/布局错误、异步间隙、平台通道
- swift-apple.md —
.ips崩溃报告、异常类型、Swift Concurrency、Objective-C 异常 - rust-cpp.md — Rust panic 和错误链;C++ 段错误、核心转储、消毒器、NDK
- other-languages.md — Python、JavaScript/TypeScript、Go、仅包含 Java 的跟踪
- worked-examples.md — 各平台的跟踪示例及完整分析