errors.Is 是过滤特定错误最可靠的方式,能穿透包装链判断 io.EOF、os.ErrNotExist 等,需先判空且自定义错误要实现 Unwrap;errors.As 用于提取带状态的错误类型;忽略错误须记录完整堆栈并标记 IGNORED;切勿无条件忽略 context.Canceled。

Go 中用 errors.Is 判断已知错误再跳过
Go 1.13 引入的 errors.Is 是过滤特定错误最可靠的方式,尤其适合忽略 io.EOF、os.ErrNotExist 或自定义错误。它能穿透 fmt.Errorf("...: %w", err) 的包装链,比直接用 == 安全得多。
常见错误现象:用 err == io.EOF 判断,结果在带 %w 包装的错误上失效;或用 strings.Contains(err.Error(), "not found"),一遇到翻译、日志前缀就崩。
- 只对明确知道是“可忽略”的错误调用
errors.Is(err, targetErr),比如errors.Is(err, os.ErrNotExist) - 自定义错误要实现
Unwrap() error并返回被包装的错误,否则errors.Is查不到底层 - 不要对
nil错误调用errors.Is—— 它会 panic,先判空:if err != nil && errors.Is(err, os.ErrNotExist) { ... }
用 errors.As 提取并过滤带状态的错误类型
当错误本身携带额外字段(比如 HTTP 状态码、重试次数),不能只靠相等判断,得用 errors.As 把错误转成具体类型再检查。典型场景是 gRPC 的 *status.Status 或自定义的 TimeoutError。
使用场景:API 调用返回 rpc error: code = Unavailable desc = connection refused,你想只忽略连接拒绝,但保留其他 Unavailable 错误(如服务过载)。
立即学习“go语言免费学习笔记(深入)”;
-
var e *status.Status,然后if errors.As(err, &e) && e.Code() == codes.Unavailable再进一步判断e.Message() - 如果错误类型没导出字段(比如内部结构体),
errors.As可能失败,这时需确保该类型实现了As(interface{}) bool方法 - 别把
errors.As和类型断言混用:err.(*MyErr)无法穿透包装,而errors.As可以
log.Printf 配合 error wrapper 做静默丢弃
不是所有错误都要返回或 panic,很多后台任务中,已知可恢复的错误(如临时网络抖动、缓存未命中)应该记录后继续,而不是层层向上抛。关键在于「记录但不中断流程」。
容易踩的坑:用 log.Printf("ignored: %v", err) 却漏掉堆栈,后续排查时不知道这个错误发生在哪一层;或者忘记加前缀,导致日志和正常业务日志混在一起难以过滤。
- 统一用
log.Printf("[IGNORED] %s: %v", "fetch-from-cache", err),方括号标记便于 grep - 如果用了
github.com/pkg/errors或 Go 1.17+ 的fmt.Errorf("%w", err),记得用%+v打印完整堆栈:log.Printf("[IGNORED] %+v", err) - 避免在热路径(如每秒万次请求的 handler)里频繁 log,考虑采样或聚合后再记,否则 I/O 成瓶颈
全局错误过滤器要小心 context cancel 的传染性
在中间件或 client 封装层做统一错误处理时,最容易误杀 context.Canceled 和 context.DeadlineExceeded —— 它们常被当成“已知错误”过滤掉,结果上游调用方收不到取消信号,goroutine 泄露。
性能影响明显:一个被忽略的 context.Canceled 可能让整个请求链路继续跑满超时时间,而不是立刻释放资源。
- 永远不要无条件忽略
context.Canceled或context.DeadlineExceeded,除非你 100% 确认当前操作是幂等且无副作用的 - 检查是否是 context 错误,优先用
errors.Is(err, context.Canceled),而不是字符串匹配 - 如果必须忽略,确保上层 context 已被取消,并且当前 goroutine 没有持有可能阻塞的 channel 或锁
真正难的不是写过滤逻辑,而是厘清每个错误在整条调用链中的语义:它是真的“可忽略”,还是只是“暂时不想看”?后者迟早会变成监控告警里的幽灵错误。










