go mod retract 是向 go 生态声明某已发布版本存在严重问题、请勿默认选用的机制,仅适用于已推送到公共代理且存在 panic、安全漏洞或误发破坏性 api 的已发布版本,需写在 go.mod 中 require 块之后、replace 之前,语法为 retract [v1.2.3] 或 retract [v1.0.0, v1.2.0]。

go mod retract 是什么,什么时候必须用
它不是删除已发布的模块版本,而是向 Go 生态“声明:这个版本有严重问题,请别自动选它”。只有当你已发布一个 v1.2.3,后来发现它存在 panic、安全漏洞或破坏性 API 误发,且无法撤回(Go Proxy 不允许删包),才需要 retract。
常见误用场景:刚发错版就急着 retract;或对本地未推送的版本执行 retract —— 这毫无意义,因为别人根本拉不到。
- 必须已推送到公共代理(如 proxy.golang.org)且被他人依赖过
- 仅适用于你拥有模块控制权的仓库(
go.mod文件可修改) - retract 后,
go get默认不再选该版本,但已有go.sum不变,不会自动降级
怎么写 retract 指令:语法、位置和生效条件
retract 必须写在模块根目录的 go.mod 文件里,放在 require 块之后、replace 之前。语法很简单:
retract [v1.2.3] retract [v1.0.0, v1.2.0]
注意方括号是必需的,版本范围支持单个版本、闭区间(含两端)、或带 + 的前缀匹配(如 [v1.2.0+) 表示 v1.2.0 及之后所有 v1.x 版本)。
立即学习“go语言免费学习笔记(深入)”;
- 多个 retract 可并列,顺序无关
- 不能 retract 当前 module 的最新 tagged 版本(即
go list -m -f '{{.Version}}'返回的那个) - retract 不影响
go mod tidy对现有依赖的清理逻辑,只影响后续go get的默认选择
retract 后用户会遇到什么变化
普通用户执行 go get example.com/mymodule 时,如果没指定版本,Go 会跳过被 retract 的版本,选下一个可用的稳定版。但以下情况不会自动响应 retract:
- 显式指定
go get example.com/mymodule@v1.2.3—— 仍能拉,只是会输出警告 - 项目中
go.mod已写死require example.com/mymodule v1.2.3——go mod tidy不会报错,也不会帮你换掉 - CI 环境使用缓存的
go.sum—— 只要校验通过,照样构建成功,retract 不触发重下载
也就是说:retract 是“温和劝退”,不是“强制熔断”。真正起作用的前提是用户主动升级或首次拉取。
容易踩的坑:签名、兼容性和传播延迟
retract 生效依赖两个关键点:模块作者发布了带 retract 的新版本(比如 v1.2.4),且该版本被 Go Proxy 索引到。这里有几个硬伤常被忽略:
- 必须用与原发布一致的私钥对新
go.mod签名,否则 proxy 拒绝收录 retract 信息(golang.org/x/mod/sumdb/note校验失败) - 如果你用的是私有 proxy 或 GOPROXY=direct,retract 信息可能压根不传播 —— 它依赖 sum.golang.org 的全局校验数据库
- 从发布 retract 版本到全球 proxy 同步完成,通常有 5–30 分钟延迟,期间用户仍可能拉到旧版
最麻烦的是:一旦 retract 写错范围(比如误写成 [v1.0.0, v999.0.0]),只能再发一个更正版,无法撤销 retract 本身。










