go build 报 permission denied 时,90% 是因 GOMODCACHE 路径不可写,需检查并显式设置可写缓存路径(如 $HOME/.cache/go/mod),验证权限后清理旧缓存再重试。

go build 报 permission denied 时,先确认是不是缓存目录写入失败
Go 构建中断在 permission denied,90% 不是代码问题,而是工具链试图往只读路径(比如 /usr/local/go/pkg/mod 或 /root/go/pkg/mod)写缓存,但当前用户没权限。这不是“你没装对”,而是 Go 在找不到可写缓存位置时的 fallback 行为。
关键判断点:go env GOMODCACHE 输出的路径是否可写?如果路径属于 root、或挂载为只读、或父目录不存在,go mod tidy 和 go build 都会卡住或报错。
- 运行
go env GOMODCACHE查看当前缓存路径 - 执行
ls -ld $(go env GOMODCACHE)检查目录权限和属主 - 尝试手动创建测试文件:
touch $(go env GOMODCACHE)/.test-write && rm $(go env GOMODCACHE)/.test-write
强制指定可写 GOMODCACHE 路径并生效
别依赖默认值——尤其在 Docker 容器、CI 环境或新系统里,GOMODCACHE 可能指向不可写位置,或根本未初始化。必须显式设置且验证。
- 临时生效(调试用):
GOMODCACHE=$HOME/.cache/go/mod go mod tidy - 永久生效:在
~/.zshrc或~/.bashrc中添加export GOMODCACHE=$HOME/.cache/go/mod - 创建目录并设权:
mkdir -p $HOME/.cache/go/mod && chmod 700 $HOME/.cache/go/mod - 重载配置后验证:
go env GOMODCACHE必须输出你指定的路径,且ls -ld显示属主为你、权限含w
清理残留只读缓存再重建
即使改了 GOMODCACHE,旧缓存仍可能干扰:比如 go mod tidy 曾失败过,部分模块已下载到只读路径但未完成解压,后续构建会反复尝试访问它,导致静默失败或超时。
- 先停掉所有正在运行的 Go 进程(尤其 IDE 的后台构建任务)
- 清除旧缓存:
go clean -modcache—— 注意:这会删掉整个GOMODCACHE目录内容,不是仅清空子目录 - 如果
go clean -modcache本身也报 permission denied,说明它正试图删只读路径 → 此时必须手动sudo rm -rf对应目录,再确保新GOMODCACHE已就位 - 重新执行
go mod tidy,观察是否开始下载依赖(而非立即报错或静默退出)
CI/容器环境里必须显式挂载 + 设置
Docker 或 GitHub Actions 中,/home/user 可能不存在,或 $HOME 为空,导致 GOMODCACHE 落到 /root/go/pkg/mod。这类环境不会自动创建目录结构,也不会提示“目录不存在”,只会卡在依赖拉取阶段,最终超时或 fallback 到系统路径。
- Dockerfile 中加:
ENV GOMODCACHE=/tmp/go/mod && mkdir -p /tmp/go/mod - GitHub Actions 中,在
steps前加:env: GOMODCACHE: /tmp/go/mod,并确保前一步有run: mkdir -p /tmp/go/mod - 禁止依赖
go mod vendor绕过缓存——vendor 只解决复现性,不解决权限;若go mod vendor执行失败,根源仍是缓存路径不可写
真正麻烦的从来不是“怎么设变量”,而是改完之后没验证 go env GOMODCACHE 是否生效、也没检查该路径是否真能写。缓存路径一旦出问题,所有依赖命令都会变成黑盒——表面无报错,实际停在某处不动,或者随机失败。动手前,先跑一遍写入测试。

















