go-multierror
是一个第三方的 Go 语言库,用于处理多个错误的聚合与管理。它由 HashiCorp 提供,非常适合需要在某些操作中收集多个错误并在最后统一返回的场景。
使用示例
顾名思义,go-multierror
包的核心功能就一个,将多个错误合并为一个错误。以下是一个典型的使用示例:
1 | package main |
示例中,我们定义了一个 *multierror.Error
类型的 errs
变量,它提供了 Append
方法可以为其追加 error
。当 step1
和 step2
都失败时,errs
中就记录了这两个 error
。
执行示例代码,得到输出如下:
1 | $ go run main.go |
可以看到,*multierror.Error
可以输出错误数量 2,以及其包含的每个 error
信息。
定制错误格式
我们还可以自定义错误的输出格式,修改上文示例中的 if errs != nil
代码块中的逻辑,将 errs.ErrorFormat
属性重新赋值为自定义函数:
1 | if errs != nil { |
这个匿名函数接收一个 error
列表,并返回 error
列表中的第一个错误信息。
执行示例代码,得到输出如下:
1 | $ go run main.go |
基于此你可以定制任何自己想要的格式。
错误兼容性
go-multierror
包兼容了 errors.Unwrap
方法,所以它可以实现错误解包操作。
示例如下:
1 | if errs != nil { |
执行示例代码,得到输出如下:
1 | $ go run main.go |
事实上,go-multierror
包完全兼容 Go 内置的 error
操作,无论是错误断言 err.(*multierror.Error)
还是 errors.Is
和 errors.As
都可以支持,你可以自行尝试。
并发场景
遗憾的是,go-multierror
包默认不支持并发操作。有如下测试代码:
1 | func TestConcurrency(t *testing.T) { |
这里并发开启 100 个 goroutine,每个 goroutine 中追加一个 error
到 errs
对象中,使用 sync.WaitGroup
等待并发操作完成。
NOTE:
如果你不熟悉
sync.WaitGroup
,可以参考我的文章「Go 并发控制:sync.WaitGroup 详解」。
执行测试代码,得到输出如下:
1 | $ go test -v -run=^TestConcurrency$ |
可以看到,测试结果失败了,预期 100 个错误,实际只得到 79 个错误。说明在并发操作过程中有部分 error
丢失了。
要解决这个问题,我们可以使用 channel
来并发安全的发送 error
对象,然后将错误聚合操作放在一个 goroutine 中处理。
示例如下:
1 | func TestConcurrencyWithChannel(t *testing.T) { |
我们对上文中的测试代码进行了改造,在所有子 goroutine 中不再直接追加 error
到 errs
对象中,而是先将其发送到带有缓冲的 channel
中,最终由 main
goroutine 从 channel
收到 err
并完成聚合操作。
执行修改后的测试代码,得到输出如下:
1 | $ go test -v -run=^TestConcurrencyWithChannel$ |
这一次测试成功了,说明我们使用 channel
的方式解决了 go-multierror
包的并发问题。
常用方法
go-multierror
包常用方法总结如下:
multierror.Append(*Error, error)
:向multierror.Error
对象添加一个新错误。如果传入的multierror.Error
为nil
,会自动创建新的实例。*Error.Error()
:将所有错误格式化为字符串,按序列号展示。*Error.ErrorOrNil()
:如果没有错误,返回nil
。否则,返回聚合后的错误。
使用场景
最后我们再来探讨下 go-multierror
的常见使用场景,我认为有如下场景比较适合使用 go-multierror
:
- 批量操作:当程序需要对一组任务(如文件处理、并发请求等)逐个执行,但每个任务可能独立失败时,使用
multierror
可以方便地记录并返回所有失败信息。此时的你是否想起了errgroup
呢? - 资源清理:当程序释放多个资源时(比如执行多个
defer
),若某些清理操作失败,可以收集这些错误并统一报告。 - 复杂流程错误管理:在长流程中,允许多个步骤分别记录错误,而不是只返回第一个错误。
总结
go-multierror
非常简单易用,它适用于需要同时管理多个错误的场景。并且完全兼容 Go error
,所以也非常实用。总之,go-multierror
是一个小巧而实用的错误管理工具,特别适合在复杂场景中对多个错误进行统一处理和报告。
不过最后我想额外提一点,go-multierror
项目采用 MPL-2.0 license 开源协议,这个协议是比 Apache 2.0 协议更加严格的开源协议,如果你的商业化软件使用并修改了其源码,则修改后的源码需要以同样协议进行开源。
下图是我制作的常见开源协议一览图,从左到右限制越来越宽松,如果你感兴趣也可以阅读我的另一篇文章「开源协议简介」。

本文示例源码我都放在了 GitHub 中,欢迎点击查看。
希望此文能对你有所启发。
延伸阅读
- go-multierror Documentation:https://pkg.go.dev/github.com/hashicorp/go-multierror@v1.1.1
- go-multierror GitHub 源码:https://github.com/hashicorp/go-multierror
- Go 错误处理指北:如何优雅的处理错误?:https://jianghushinian.cn/2024/10/01/go-error-guidelines-error-handling/
- Go 并发控制:sync.WaitGroup 详解:https://jianghushinian.cn/2024/12/23/sync-waitgroup/
- Go 并发控制:errgroup 详解:https://jianghushinian.cn/2024/11/04/x-sync-errgroup/
- 开源协议简介:https://jianghushinian.cn/2023/01/15/open-source-license-introduction/
- 本文 GitHub 示例代码:https://github.com/jianghushinian/blog-go-example/tree/main/error/go-multierror
- 本文永久地址:https://jianghushinian.cn/2025/03/23/go-multierror/
联系我
- 公众号:Go编程世界
- 微信:jianghushinian
- 邮箱:jianghushinian007@outlook.com
- 博客:https://jianghushinian.cn
- GitHub:https://github.com/jianghushinian