error-handlinglisted
Install: claude install-skill Wade-DevCode/awesome-coding-skills-cn
# 错误处理
## 何时用
- 写任何涉及 IO、网络、数据库、外部 SDK 调用的代码时。
- 在函数/方法中加 try-catch/try-except,需要确定该怎么处理时。
- 联调时前端反馈"不知道哪里出错了"或日志里找不到报错原因时。
- code review 发现 catch 块为空、或者只有 `console.log(e)` 时。
## 核心规则
### 1. 不吞异常:catch 块必须有实质处理
**规则:** `catch`/`except` 块里必须有真正的处理动作——记录日志、触发回滚、重新抛出或转换为业务错误;禁止空 catch 块,禁止仅打印后继续正常流程假装没发生过。
**为什么:** AI 生成代码时,"先写个 try-catch 让它跑起来"是最常见的反模式——`catch (e) {}` 或 `except: pass`。空 catch 会把真实的数据库连接失败、磁盘写入错误、第三方 API 超时全部静默吞掉,函数返回"成功",上层完全感知不到异常,日志里没有任何线索,用户看到的是数据没有保存但页面显示"操作成功"。定位这类 bug 通常要花几倍时间,因为所有的证据都被主动销毁了。
**怎么做:**
- 能处理就处理(重试、降级、返回默认值),并记录 warn 级日志。
- 不能处理就重新抛出(`throw`/`raise`),让上层决定。
- 需要转换语义时,把底层异常包裹成业务异常再抛:`throw new PaymentFailedException("支付网关超时", cause=e)`。
- `finally` 块做资源清理,不要把清理逻辑写在 catch 里然后 return 提前跳出。
---
### 2. 错误分类:可预期错误与意外错误分开处理
**规则:** 明确区分两类错误——可预期的业务错误(用户输入非法、资源不存在、权限不足)和意外的系统错误(空指针、数据库宕机、bug);前者用业务异常类表达,后者进入全局 handler 并触发告警。
**为什么:** AI 生成的代码经常把所有异常一律 `catch (Exception e)` 然后返回 500——校验失败返回 500、资源不存在返回 500、真正的 bug 也是 500。监控告警全是噪音,用户看到的错误信息毫无意义,oncall 工程师不知道哪些 500 需要紧急处理、哪些是正常的业务错误被错误分类了。错误分类是可观测性的基础,混在一起会让整个告警体系失效。
**怎么做:**
```python
# 业务异常基类(可预期,映射到 4xx)
class AppError(Exception):
def __init__(self, code: str, message: str, http_status: int = 400):
self.code = code
self.message = message
self.http_status = http_status
class ResourceNotFoundError(AppError):
def __init__(self, resource: str, resource_id):
super().__init__("RESOURCE_NOT_FOUND", f"{resource} {resource_id} 不存在", 404)
# 意外错误不捕获,让全局 ha