Go module checksum 缺失时为什么只在 CI 失败
来源:17golang原创
时间:2026-09-15 16:09:25 487浏览 收藏
本地执行 go test ./... 没问题,CI 却提示缺少 module checksum,最常见的原因不是代码在两台机器上“随机不同”,而是本地模块缓存已经有旧的校验结果,CI 使用干净缓存并且不允许构建过程改写 go.sum。Go 会依据主模块的 go.sum 校验下载到的 .mod 和模块压缩包;缺少条目时,能联网且可写的本地环境可能顺手补上,CI 的只读环境则直接失败。
- 先用干净模块缓存复现,不要只清理编译缓存。
- 用
go mod tidy生成应提交的校验条目,再检查是否混入了无关依赖。 - CI 使用
-mod=readonly固定输入,私有模块用GOPRIVATE处理,不要为了过构建关闭校验。
为什么本地通过而 CI 只报 module checksum 缺失
我排查这类问题时,第一步不是给 CI 加更多重试,而是把本地的模块缓存当成一个隐藏输入。GOCACHE 影响编译结果缓存,GOMODCACHE 影响模块文件是否已经下载;后者命中时,本地可能根本没有走到“为当前主模块补一行 go.sum”的路径。CI 若从空缓存开始,缺失的 go.mod 或 zip 校验就会暴露出来。
公共模块通常经过 GOPROXY 下载,并由 checksum database 提供一致性校验。go.sum 不是简单的安装清单,而是主模块认可过的哈希集合;同一模块的 版本 和 版本/go.mod 可能各有一行。可以把本地和 CI 的关键输入先列出来:
| 现象 | 优先检查 | 判断 |
|---|---|---|
| 本地通过,CI 失败 | GOMODCACHE、-mod | 缓存或只读策略不同 |
| 每台机器都失败 | go.sum 是否纳入提交 | 项目确实缺少校验条目 |
| 只在私有依赖失败 | GOPRIVATE、GONOSUMDB | 公共校验服务不应接管该模块 |

先用干净缓存确认缺的到底是哪一行
在与 CI 相同的模块目录下复现,重点是清空或更换 GOMODCACHE,而不是只执行 go clean -cache。下面的命令把下载目录放到临时位置,并让构建先以只读方式运行:
# 使用临时模块缓存,避免本机旧依赖掩盖 go.sum 问题
tmpmod=$(mktemp -d)
GOMODCACHE="$tmpmod" go mod download
# 只读模式不允许构建顺手改写 go.mod 或 go.sum
GOMODCACHE="$tmpmod" go test -mod=readonly ./...
# 检查模块缓存中的文件是否被改动
GOMODCACHE="$tmpmod" go mod verify
# 用完临时目录后删除,避免把一次排障缓存当成项目依赖
rm -rf "$tmpmod"
如果第二条命令明确指出某个模块缺少 go.sum 条目,问题已经从“CI 偶发失败”收敛为可提交的依赖元数据差异。若是下载失败,则继续看 GOPROXY、证书、网络和私有仓库权限,不要把网络错误误判为 checksum 缺失。
用 go mod tidy 补齐,但先看清变更范围
在依赖来源可访问的开发环境执行 go mod tidy,它会根据源码、测试和构建约束补充缺失哈希并删除不再需要的条目。命令完成后,先查看差异,再运行测试;不要直接把整个工作区的变化打包提交。
# 根据当前源码和构建约束整理依赖元数据
go mod tidy
# 只检查依赖文件的变化,确认没有意外升级版本
git diff -- go.mod go.sum
# 用只读模式复跑,确保构建不再依赖隐式写入
go test -mod=readonly ./...
# 校验模块缓存中的内容没有被修改
go mod verify
如果 go mod tidy 删除了看似“以后可能会用”的哈希,不必为了保守把它们全部加回去;go.sum 可以保留多版本记录,但当前命令只应提交与当前模块图和测试范围一致的变更。真正需要人工确认的是 go.mod 是否发生了版本升级,以及生成代码、平台构建标签是否改变了依赖集合。

把 CI 环境固定成可复现的输入
修复提交后,CI 应明确表达“构建不能替我修改依赖文件”。例如:
# CI 中固定公共模块代理;私有模块由 GOPRIVATE 匹配
export GOPROXY="https://proxy.golang.org,direct"
export GOPRIVATE="example.com/internal/*"
# 只读构建:缺少 go.sum 时立即失败,提示开发者修复提交
go test -mod=readonly ./...
# 依赖缓存可复用,但不能成为唯一的正确性来源
go mod verify
GOPRIVATE 会为匹配的模块提供私有模块默认行为,通常也影响 GONOPROXY 和 GONOSUMDB。如果企业使用自建代理,应按代理的认证和校验方案配置;不要简单设置 GOSUMDB=off 来掩盖公共依赖缺少校验。只有在明确的私有模块边界内,才讨论是否绕过公共 checksum database。
常见问题
只提交 go.sum,不改 go.mod 可以吗?
如果依赖版本没有变化,通常可以,但仍应检查 tidy 的完整差异;若 go.mod 同时需要补充或调整,就应一起提交。
为什么删除本地缓存后问题才出现?
因为缓存保存了已下载模块,清空 GOMODCACHE 后,Go 才会重新读取主模块的校验输入并暴露缺失条目。
go mod verify 能替代 go test 吗?
不能。它主要验证模块缓存内容是否被修改,不能替代编译、测试和依赖图解析;两者应承担不同检查职责。
-
Golang · Go问答 | 36分钟前 | 依赖管理 · go · module · retract · 版本选择 · go mod download Go module retract Go 模块撤回 Go 依赖版本缓存 go list -retracted368 收藏
-
113 收藏
-
367 收藏
-
428 收藏
-
357 收藏
-
256 收藏
-
180 收藏
-
Golang · Go问答 | 2小时前 | 单元测试 · 错误处理 · go · t.Cleanup · testing.T · Go testing.T Cleanup失败 Go t.Cleanup错误处理 Go测试清理函数继续执行 Go测试失败不终止 Go测试资源释放排查267 收藏
-
156 收藏
-
460 收藏
-
330 收藏
-
456 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习