Go依赖包的error必须显式检查,不可忽略;应使用errors.Is和errors.As判断具体错误类型;避免盲目包装错误;第三方SDK需按其文档约定处理错误。

Go 依赖包里返回的 error 值必须显式检查,不能忽略
Go 没有异常机制,所有错误都通过返回 error 类型值传递。依赖包(比如 net/http、database/sql、第三方库如 gorm 或 redis/go-redis)只要可能失败,就一定会在函数签名中暴露 error。不检查它,程序大概率会在后续 panic 或行为异常。
常见错误现象:调用 json.Unmarshal 后没看 err,结果结构体字段全是零值;或 db.QueryRow 返回 sql.ErrNoRows 却当正常数据处理,导致空指针 panic。
- 永远用
if err != nil立即判断,不要攒到函数末尾统一处理 - 不要写
_, _ = someFunc()这类丢弃 error 的代码 —— Go vet 和 staticcheck 都会报errors.Unused - 对可预期的错误(如
os.IsNotExist、sql.ErrNoRows)做类型/值判断,而非仅靠字符串匹配
用 errors.Is 和 errors.As 判断依赖包返回的具体错误类型
很多依赖包会封装底层错误(比如 io/fs 包把系统调用错误转为 fs.PathError),直接用 == 或 strings.Contains(err.Error(), "...") 不可靠,且易被包装层破坏。
立即学习“go语言免费学习笔记(深入)”;
-
errors.Is(err, fs.ErrNotExist)判断是否是“文件不存在”这类哨兵错误 -
errors.As(err, &pathErr)尝试解包成具体错误类型,用于获取路径、操作名等上下文信息 - 第三方包如
github.com/pkg/errors(已归档)或golang.org/x/xerrors(已合并进标准库)的语义已被errors包覆盖,无需额外引入
示例:
if errors.Is(err, os.ErrPermission) {
log.Printf("permission denied on %s", path)
} else if errors.As(err, &pathErr) {
log.Printf("failed to open %s: %v", pathErr.Path, pathErr.Err)
}
不要用 fmt.Errorf("wrap: %w", err) 盲目包装所有依赖错误
依赖包返回的 error 本身往往已含足够上下文(比如 http.Client.Do 返回的 *url.Error 包含 URL 和底层 net.Error)。盲目用 %w 包装一层,只会让错误链变长、堆栈混乱,反而掩盖关键信息。
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
该包装时才包装:
- 当你需要添加业务语义(如 “failed to fetch user profile from auth service”)
- 当原始错误缺少必要上下文(比如只返回
"invalid input",但你知道是哪个字段出问题) - 避免连续多次包装:不要
fmt.Errorf("step1: %w", fmt.Errorf("step2: %w", err))
调试时可用 fmt.Printf("%+v", err) 查看完整错误链和栈帧 —— 这依赖 %+v 对实现了 Unwrap() 的错误的支持。
第三方 SDK 错误处理要查清其文档约定,别假设和标准库一致
像 aws-sdk-go-v2、google.golang.org/api、stripe/stripe-go 这些 SDK,错误模型和标准库不同:有的返回自定义错误类型(如 *smithy.OperationError),有的用特定字段标识重试性(ShouldRetry() 方法),有的甚至把 HTTP 状态码藏在 error 的某个字段里。
- 不要直接
errors.Is(err, context.DeadlineExceeded)—— AWS SDK 的超时错误不是这个类型,得用IsErrorType(err, "RequestExpired")或类似方法 - 读 SDK 的
error.go或官方错误处理示例,确认它是否支持errors.As解包 - 注意有些 SDK 把网络错误和业务错误混在一个 error 类型里,需结合 HTTP 状态码或错误码字段区分
最容易被忽略的是:SDK 的错误对象可能包含可序列化的字段(如 ErrorCode、ErrorMessage),比 err.Error() 更适合日志结构化或告警分类 —— 别只打印字符串。









