Go Modules - checksum mismatch 错误解决
Table of Contents
问题描述
本地执行了 go clean -modcache
后,执行 go mod download
,出现错误:
verifying git.xxx.com/neirong/app-framework@v0.7.8/go.mod: checksum mismatch
downloaded: h1:/8A+C1sjRPdK/06I7b2egOVjo8+ECKV3vJ3Cqz5vEzc=
go.sum: h1:7HfHuMOcinPkTDMNEf6Otcy4+TBvDQ/+f2UO0N23l3o=
SECURITY ERROR
一般遇到 checksum mismatch 错误,直接删除 go.sum 后,执行 go clean -modcache
,再执行 go mod download
即可。我也确实这么做的,执行后,不再报错。当我把新的 go.sum 文件提交到 GitLab,跑 lint 时出现同样的错误:
verifying git.xxx.com/neirong/app-framework@v0.7.8/go.mod: checksum mismatch
downloaded: h1:/8A+C1sjRPdK/06I7b2egOVjo8+ECKV3vJ3Cqz5vEzc=
go.sum: h1:7HfHuMOcinPkTDMNEf6Otcy4+TBvDQ/+f2UO0N23l3o=
SECURITY ERROR
即 app-framework@v0.7.8/go.mod 下载后计算得到的 hash(老的)与新生成 go.sum 里的 hash(新的)不一致。
解决过程
-
判断 GitLab 跑 lint 时是否有模块缓存,结论:GitLab 跑 lint 是新起的容器,没有缓存
-
因为 go env 的 proxy 设置了公司的 proxy 地址,且 app-framework@v0.7.8 是私有模块,考虑 proxy 代理中有该模块老的缓存。然而找其他同事,删除 go.sum,执行
go clean -modcache
后,再执行go mod download
,生成新 go.sum 中的 app-framework@v0.7.8 的 hash 还是老的,也就是说不同人执行相同的操作,得到的 hash 是不一致的 -
通过 go-checksum 工具,手动计算 app-framework@v0.7.8 模块的 hash,可以确定我自己后来生成的 hash 是正确的:
~/temp/app-framework go-checksum go.mod
file: go.mod
{
"Hash": "3efa7cc5648863b16b19e6e8b781f40bf4d0e95137b5a5f97e6468a00dc3f45a",
"HashBase64": "Pvp8xWSIY7FrGebot4H0C/TQ6VE3taX5fmRooA3D9Fo=",
"HashSynthesized": "ec77c7b8c39c8a73e44c330d11fe8eb5ccb8f9306f0d0ffe7f650ed0ddb7977a",
"HashSynthesizedBase64": "7HfHuMOcinPkTDMNEf6Otcy4+TBvDQ/+f2UO0N23l3o=",
"GoCheckSum": "h1:7HfHuMOcinPkTDMNEf6Otcy4+TBvDQ/+f2UO0N23l3o="
}
- 随后发现是 proxy 中缓存了不正确的模块导致的,清理 proxy 缓存,GitLab 的 lint 不再报错,这一问题得到解决
Q&A
1. 是什么原因导致同一个版本的模块,go.sum 文件里前后存在 hash 不一致现象?
go mod 拉取指定版本模块时,先找有没有这个版本的 tag,如果找到该 tag,直接拉取;如果没有对应的 tag,找指定版本同名的 branch,如果找到同名的 branch,直接拉取。如果是先有 branch,有人通过 proxy 拉取后,会缓存到 proxy 上。如果之后该模块在该 branch 上有修改,然后再打 tag,就会导致模块文件发生改变,hash 也会随之该改变,而 proxy 一直缓存是老的模块。
2. 如何避免 1 中的问题?
branch 名与 tag 不要同名,防止其他人使用了未正式发布的版本。
3. 既然 proxy 缓存了老的模块,为什么不同人删除 go.sum 文件,执行 go clean -modcache
后,再执行 go mod download
,有的人还是老的模块,有的人获取到的是新的模块?
是因为 go env 中的 gonoproxy 环境变量导致。我本地 GONOPROXY=“git.xxx.com” ,即下载 git.xxx.com 上的模块,不走 proxy,直接从源站获取。而 gonoproxy 环境变量中没有设置 git.xxx.com 内容时,是从 proxy 获取(命中了老的缓存)。GONOPROXY 官方释义:
GONOPROXY — list of glob patterns of module path prefixes that should not be downloaded from a proxy. The go command will download matching modules from version control repositories where they’re developed, regardless of GOPROXY.