errors.Is 用于判断错误链中是否存在指定错误值,需用 %w 包装且目标错误须为可比较变量;errors.As 用于提取错误链中最内层指定类型的错误实例,二者均穿透包装、支持自定义方法,但要求正确构建错误链。

errors.Is 判定错误是否等于某个目标错误
它用来判断一个错误链中是否存在某个具体的错误值(不是类型,是值相等),比如你用 errors.New("timeout") 创建的错误,或者某个包导出的预定义错误变量(如 io.EOF)。它不关心错误包装了多少层,只看链上有没有完全相同的错误值。
常见错误现象:errors.Is(err, io.EOF) 返回 false,但你知道 err 最终来自读取结束——可能因为中间用了 fmt.Errorf("read failed: %w", io.EOF) 包装过,而 errors.Is 能穿透这个 %w,所以通常能命中;但如果写成 fmt.Errorf("read failed: %v", io.EOF)(没用 %w),那错误链就断了,errors.Is 就查不到 io.EOF。
- 必须确保错误链用
%w正确包装,否则errors.Is无法向下遍历 - 目标错误必须是可比较的:不能传入临时
errors.New("xxx")作比较,因为每次调用都生成新地址,值不等;应使用包级变量(如sql.ErrNoRows)或提前定义好的错误值 - 对自定义错误类型,如果实现了
Is(error) bool方法,errors.Is会优先调用它,而不是靠默认的指针/值比较
errors.As 提取底层错误值到指定类型变量
当你需要从错误链里“捞出”某个具体类型的错误实例(比如 *os.PathError 或自定义的 *MyAppError),就得用 errors.As。它会沿着链逐层检查每个错误是否可以类型断言为你要的目标类型,并把第一个匹配的结果赋给传入的指针变量。
使用场景:你想获取 os.Open 失败时的原始路径信息,或者想判断某个错误是否由你的 SDK 内部的 *HTTPError 导致并读取其 StatusCode 字段。
立即学习“go语言免费学习笔记(深入)”;
- 第二个参数必须是指向接口或具体类型的指针,比如
&pathErr,不是pathErr;传错会导致 panic 或静默失败 - 如果错误链里有多个同类型错误(比如嵌套两次
*os.PathError),errors.As只返回最内层那个(即最早被包装的那个) - 自定义错误类型若想支持更灵活的匹配逻辑,可实现
As(interface{}) bool方法,errors.As会优先调用它
别把 errors.Is 和 errors.As 当成类型断言替代品
它们解决的是“错误链中是否存在某值/某类型”的问题,不是“当前错误是不是这个类型”。直接用 err.(*os.PathError) 只检查最外层错误,而 errors.As 会穿透整个链;同样,err == io.EOF 只比表层,errors.Is 才是真正可靠的链式判断。
性能影响很小,但要注意:每次调用都会遍历整个错误链,深度过大的链(比如上百层)可能带来可观开销;不过现实中极少出现,除非手动构造恶意错误链。
- 不要在 hot path(如高频循环内)反复调用
errors.Is去判断同一个固定错误值,可考虑提前提取或缓存判断结果 - 兼容性上,
errors.Is和errors.As自 Go 1.13 引入,低于该版本需用x/xerrors(已废弃)或自行实现简易版 - Go 1.20+ 中,
fmt.Errorf的%w是唯一被官方支持的错误包装方式;其他字符串拼接、结构体字段赋值等方式都会切断链
error 链断裂的典型信号和自查方法
当你发现 errors.Is 或 errors.As 突然失效,大概率是错误链断了。最典型的信号就是:上游返回的错误明明包含某个已知错误,但下游怎么也 match 不上。
自查方法很简单:打印 fmt.Printf("%+v", err),观察输出里有没有 Unwrap() error 相关字段或嵌套结构;如果只有纯字符串、没有缩进或括号嵌套,基本就是链断了。
- 检查所有错误构造位置,确认是否统一用了
%w,尤其注意日志封装、中间件包装、HTTP handler 错误返回等易忽略点 - 第三方库如果没用
%w包装(比如老版本github.com/pkg/errors),它的错误无法被errors.Is/As正确识别,需升级或加一层适配 - HTTP 客户端错误(如
net/http)本身不包装底层连接错误,所以errors.Is(err, syscall.ECONNREFUSED)通常失败;得先用errors.As提取出*url.Error,再对其Err字段做二次判断
%w,就断一节。










