go mod vendor 离线失败的根本原因是本地未执行 go mod download 完整拉取依赖,导致 gocache 中缺失模块;必须确保 go list -m all 的每个模块在 $gocache/pkg/mod/cache/download/ 下存在 zip 和 info 文件,且 vendor/modules.txt 与 go.mod、vendor 目录严格一致。

go mod vendor 为什么在离线构建时经常失败
go mod vendor 本身不下载新模块,它只把 go.mod 里已记录的依赖复制到 vendor/ 目录。但很多人执行时遇到 no required module provides package 或 cannot find module providing package,根本原因是:本地 go.mod 里记录的模块版本,在 GOPATH 或 GOCACHE 里压根没存全——尤其是跨机器同步项目后,go mod download 没跑过,vendor 就成了无源之水。
- 离线前必须确保当前机器已完成完整依赖拉取,即
go mod download成功执行且无报错 -
go list -m all输出的每个模块,都得能在$GOCACHE/pkg/mod/cache/download/下找到对应 zip 和 info 文件 - 如果用 CI 构建机生成 vendor,别直接 rsync 项目目录,要连
$GOCACHE一起打包(或用go mod download -json验证完整性)
go mod vendor 的实际行为与常见误操作
go mod vendor 默认只 vendor 当前 module 的直接和间接依赖,但不会 vendor 测试依赖(如 _test.go 里 import 的包)、不会 vendor replace 后的原始路径、也不会处理 //go:embed 引用的非 Go 文件。
- 若项目含集成测试且测试代码 import 了额外包,需先运行
go test -mod=mod -c ./...触发测试依赖解析,再go mod vendor - 有
replace语句时,vendor/里放的是被 replace 后的目标路径(比如replace example.com/a => ../a,则vendor/example.com/a/是空的,实际代码来自本地../a) -
go mod vendor -v可看到哪些包被跳过,重点关注标有(not in vendor)的行 - 不要手动删
vendor/modules.txt—— 它是 vendor 的快照,缺失会导致go build -mod=vendor拒绝加载 vendor
离线构建时 go build -mod=vendor 的硬性前提
go build -mod=vendor 不是“有 vendor 目录就能用”,它会严格校验三件事:当前 module 的 go.mod、vendor/modules.txt、以及 vendor/ 目录结构三者是否完全一致。任一环节出偏差,就会 fallback 到 module mode 并报错。
- 构建机必须清空
GOPATH和GOCACHE(或设为临时路径),否则可能混入旧缓存导致校验失败 -
vendor/modules.txt必须由同一台机器、同一版 Go(至少主次版本一致)生成,Go 1.18 和 1.21 对 checksum 计算方式有差异 - 如果项目用了
//go:build条件编译,某些平台特定依赖可能未被go mod vendor收录,需在目标平台上生成 vendor -
go env -w GO111MODULE=on必须生效,否则-mod=vendor被忽略
vendor 目录瘦身与最小化交付的取舍点
go mod vendor 默认把所有依赖(包括测试用的 golang.org/x/tools 这类重型包)全拷进去,一个中型项目 vendor 常超 200MB。但删减要极度谨慎。
立即学习“go语言免费学习笔记(深入)”;
- 删
vendor/<em>/testdata</em>或_test.go通常安全,但某些包(如github.com/gogo/protobuf)的 testdata 被生产代码反射调用,删了会 panic - 不要删
vendor/modules.txt或改其中 checksum,哪怕只是空格变动也会让go build -mod=vendor拒绝启动 - 如果用 Bazel 或 Nix 等构建系统,
vendor反而增加维护成本,不如固定GOCACHE+go mod download归档 - 真正离线环境(如航天器 onboard 系统),建议用
go mod verify+sha256sum vendor/*<em>/</em> .mod .sum全量校验,而非只信目录存在
vendor 不是缓存,是契约。它要求你对每一行 go.mod、每一个 replace、每一次 go 版本升级,都保持可追溯的构建闭环。漏掉任意一环,离线时暴露的不是技术问题,是协作断点。










