go get 在私有模块上失败提示“not found”的根本原因是本地环境变量配置错误,包括 goprivate 未正确匹配域名、goproxy 被设为 direct 或为空、goinsecure 与 goproxy 冲突等,导致 go 跳过认证走无凭证请求而返回 404。

为什么 go get 总在私有模块上失败,却提示“not found”?
不是网络不通,也不是 Git 仓库地址错了——真正拦路的是本地环境变量。Go 在解析私有模块路径时,会优先读取 GOPRIVATE、GOPROXY 和 GOINSECURE 这三个变量,只要其中任一值被意外覆盖(比如 shell 配置里写了 GOPROXY=direct 或漏配 GOPRIVATE),go get 就会跳过认证流程,直接走无凭证的 HTTP 请求,最终 404。
常见诱因包括:
-
GOPROXY被设为direct或空字符串,导致 Go 绕过代理、也不走私有源认证 -
GOPRIVATE没包含完整域名前缀(如只写git.internal,但模块路径是git.internal/team/repo),Go 不识别为私有域 -
GOINSECURE与GOPROXY冲突:设了GOINSECURE却没配GOPROXY=direct,Go 仍尝试走代理并失败
GOPRIVATE 的匹配规则到底怎么写才生效?
Go 对 GOPRIVATE 的匹配是前缀匹配,不是通配符或正则。它只认 * 作为通配符,且仅支持开头或结尾,不支持中间。
正确写法示例:
- 匹配所有子路径:
GOPRIVATE=git.internal,github.company.com - 匹配带通配前缀的域名:
GOPRIVATE=*.internal,*.company.com - 错误写法(无效):
GOPRIVATE=git.internal/*、GOPRIVATE=git.internal/**、GOPRIVATE=git.*.com
注意:如果模块路径含端口(如 git.internal:8080/repo),GOPRIVATE 必须包含端口号,即写成 GOPRIVATE=git.internal:8080,否则不匹配。
如何验证当前环境变量是否真正在生效?
别只看 echo $GOPRIVATE——Go 命令实际读取的是启动时的环境快照,可能被 IDE、shell 子进程或 CI 环境覆盖。最可靠的方式是让 Go 自己吐出当前解析结果:
go env -w GOPRIVATE=git.internal<br>go list -m -json all 2>/dev/null | grep -i private
更直接的验证法:
- 运行
go get -x git.internal/repo@v1.2.3,观察日志中是否出现skip proxy或using local fetch字样;若仍出现GET https://proxy.golang.org/...,说明GOPRIVATE未命中 - 临时清空所有代理相关变量测试:
GOPROXY= GOINSECURE= GOPRIVATE=git.internal go get git.internal/repo,成功则证明原配置有冲突
CI/CD 和多用户共享机器上最容易忽略的陷阱
开发机上配好了 GOPRIVATE,CI 流水线却依旧失败——大概率是构建镜像或 runner 用户没继承 shell 的环境变量,或者用了非 login shell 启动。
必须显式注入:
- GitHub Actions 中,不能只靠
env:块,要在steps里每步都加env:,或用go env -w提前写入 - Docker 构建时,
ENV GOPRIVATE=git.internal必须出现在FROM golang:1.21之后、RUN go mod download之前 - 公司内网 Jenkins 节点若用 systemd 启动 agent,需在 service 文件中用
Environment=显式声明,否则环境变量不可见
另一个隐形坑:某些 Go 版本(如 1.18 初期)对 GOPRIVATE 大小写敏感,写成 git.INTERNAL 就不匹配——统一用小写最稳妥。











