根本原因是Go 1.14+默认忽略vendor目录,必须显式指定-mod=vendor参数;若缺失该参数、go.mod无效、vendor不完整或go.sum校验失败,仍会fallback到模块模式报错。

go build -mod=vendor 为什么还是报 cannot find module
根本原因不是 vendor 目录没生成,而是 go build 没真正走 vendor 路径——Go 1.14+ 默认忽略 vendor,必须显式加 -mod=vendor 参数。漏掉这个,哪怕 vendor/ 目录存在、modules.txt 齐全,也会 fallback 到模块模式并尝试联网解析。
常见误操作包括:
- 只运行了
go mod vendor,但构建时写成go build ./cmd/app(缺参数) - CI 脚本里用了
go test或go install,没加-mod=vendor - 设了
GOFLAGS="-mod=vendor",但被子 shell 或 Docker 环境变量覆盖 - 项目根目录下没有有效的
go.mod(比如被误删或格式错误),导致go build根本不识别模块上下文
go mod vendor 前必须确保 go.mod 和 GOCACHE 完全一致
go mod vendor 不下载新包,它只复制本地缓存里的代码。如果 go list -m all 显示 23 个模块,但 $GOCACHE/pkg/mod/cache/download/ 下只有 18 个 zip 包,vendor 就会缺依赖,编译时直接报 no required module provides package。
离线前必须在有网机器上跑通这三步:
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 用目标 Go 版本(如
go1.21.6)执行go mod tidy,补全go.sum并清理冗余 require - 执行
go mod download -x,观察输出是否所有模块都落盘到download/目录;重点检查带// indirect标记的模块是否也下载完成 - 再运行
go mod vendor,生成后用diff -u 校验一致性
replace 本地路径和 cgo 依赖在 vendor 中的处理陷阱
replace 语句指向本地文件系统(如 replace example.com/a => ../a)时,go mod vendor 默认跳过它——vendor/ 里不会出现 example.com/a,也不会把 ../a 拷进去。编译时若启用了 -mod=vendor,就会因找不到包而失败。
cgo 更隐蔽:即使 vendor 完整,启用 CGO_ENABLED=1 后,net、os/user 等包仍会调用系统库。离线机若没装 libc6-dev 或 libpthread.a,go build -mod=vendor 会卡在 cannot find -lc。
应对方式:
- 对 replace 本地路径:先用
go mod edit -replace=example.com/a=github.com/xxx/a@v1.2.3临时切回远程版本,vendor 完成后再改回来;或手动cp -r ../a vendor/example.com/a并确保vendor/modules.txt手动补上对应行 - 对 cgo 依赖:离线机必须预装对应开发包(如 Ubuntu 要
apt install build-essential libc6-dev),或干脆设CGO_ENABLED=0——但得接受 DNS 解析退化为纯 Go 实现(可能读不到/etc/resolv.conf)
GOSUMDB=off 和 go.sum 的校验关系不能省略
go build -mod=vendor 仍会读 go.sum 校验 vendor 里代码的哈希值。如果 vendor 是旧版生成的,而 go.sum 已被新 go mod tidy 更新,就会报 verifying github.com/xxx@v1.2.3: checksum mismatch。
离线环境下,go.sum 不能删,也不能靠 GOSUMDB=off 绕过——后者只是禁用远程校验,本地 go.sum 文件仍会被比对。正确做法是:
- 每次
go mod tidy后,立刻跟go mod vendor,保证go.sum和vendor/modules.txt同步更新 - 若已离线且
go.sum过期,唯一安全方式是回到有网机器重新go mod tidy && go mod vendor,再打包整个项目目录(含go.sum、vendor/、go.mod) -
GOSUMDB=off仅用于极端调试场景,生产离线构建中它不解决 checksum mismatch,反而掩盖真实不一致问题
go build -mod=vendor 这一整套参数组合,以及它背后对 go.mod、go.sum、vendor/modules.txt 三者严格一致性的校验。少一个环节,就不是离线,只是“看起来像”。

















