go.sum校验失败不是缓存损坏,而是go严格比对go.sum记录值、缓存.info文件和实际源码三者哈希,任一不匹配即拒绝使用缓存并报错。

go.sum 校验失败时,缓存不是“坏了”,而是被拒绝了
你看到 checksum mismatch 错误,第一反应常是“缓存损坏”,其实不是。Go 在构建前会严格比对三处 checksum:你项目 go.sum 里记录的值、缓存目录中对应模块版本的 .info 文件、以及实际源码内容。只要任一不匹配,就直接报错并跳过该缓存——哪怕文件完整存在,也不会用。
常见触发场景:
- 手动编辑过
$GOPATH/pkg/mod/xxx@v1.2.3/下的源码(哪怕只改一行注释) -
go.sum没提交进 Git,不同人本地生成的校验和不一致 - 私有模块代理配置漏掉
direct,导致部分模块走 direct 下载,但.info未按预期生成 - 磁盘满导致
go mod download写入中断,.info文件残缺或为空
CI 中缓存 $HOME/go/pkg/mod 但没命中?检查两个路径是否都挂载了
很多 CI 流水线只缓存 ~/.cache/go-build(即 GOCACHE),却忘了模块缓存根本不在那儿——它在 $HOME/go/pkg/mod(Linux/macOS)或 %USERPROFILE%\go\pkg\mod(Windows)。只挂载前者,go mod download 仍会重拉所有依赖。
GitHub Actions 示例中必须同时缓存:
${{ env.HOME }}/go/pkg/mod${{ runner.os == 'Windows' && env.LOCALAPPDATA || env.HOME }}/.cache/go-build
另外,确保 GO111MODULE=on 和 GOPROXY=https://goproxy.cn 在所有步骤中生效,避免因环境变量丢失 fallback 到 slow 或不可达的源。
go clean -modcache 是“一键清零”,但它不碰 go.sum,也不影响版本锁定
执行 go clean -modcache 后,$HOME/go/pkg/mod 目录被清空,但 go.mod 和 go.sum 完全不变。下次 go build 或 go mod download 会重新下载所有依赖,并基于 go.sum 重新生成带校验的 .info 文件。
这不是“重置依赖”,只是清本地副本。真正危险的操作是 go mod tidy -compat=1.20 这类修改 go.mod 的命令,或者手动删 go.sum 后再 go mod download——这会导致校验和重新计算,可能引入未审核的 patch 版本。
交叉编译 + CGO_ENABLED=0 时,GOCACHE 和 pkg/mod 都要独立管理
当你在 CI 中为不同平台构建(如 GOOS=linux GOARCH=arm64),GOCACHE 会自动按目标平台分隔缓存条目,但 pkg/mod 里的源码是通用的。问题在于:CGO_ENABLED=0 会改变编译输入指纹,导致同一份源码在不同 CGO 状态下生成完全不同的缓存 blob。
这意味着:
- Linux amd64 + CGO_ENABLED=1 的缓存,不能被 Linux arm64 + CGO_ENABLED=0 复用
- 但
pkg/mod缓存仍可复用——因为源码本身没变 - 所以 CI 中建议:对每个
GOOS/GOARCH/CGO_ENABLED组合单独设置GOCACHE路径,避免互相污染;而pkg/mod可全局共享
最易被忽略的一点:CI 环境若未固定 Go minor 版本(比如用 go@1.x 而非 go@1.22.5),不同 Go 版本生成的缓存 blob 不兼容,GOCACHE 命中率会断崖式下跌——这不是 bug,是设计使然。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











