golangci-lint 默认成功退出(返回0)即使存在SA1019或unused等报错;必须在.golangci.yml顶层显式配置issues-exit-code: 1,且确保staticcheck等关键linter已启用、配置文件名正确、路径有效、未启用--fast模式,才能使检查失败触发非零退出码。

golangci-lint 默认不因检查失败而退出非零码——你看到 CI 流水线“成功通过”但其实漏了一堆 SA1019 或 unused 报错,大概率是它安静地以 0 退出了。
为什么 golangci-lint run 有时返回 0 却有报错
默认行为是:只要 lint 过程本身没 panic、没超时、没读取文件失败,哪怕输出 200 条 staticcheck 错误,golangci-lint run 仍返回 0。这不是 bug,是设计——它把“运行成功”和“代码合规”视为两件事。
- CI 脚本里只写
golangci-lint run,没加任何控制参数 → 实际等于“只验证工具能跑通”,毫无质量门禁作用 - VS Code 或 GoLand 集成中没启用
--issues-exit-code,编辑器就收不到错误信号,波浪线不显示 - 旧配置(如 v1.4x)可能还残留
issues-exit-code: 1写法,但新版已废弃,必须用issues-exit-code顶层字段
如何让失败真正中断 CI 或本地命令链
必须显式启用 exit-on-issue 机制,且注意字段位置和值语义:
-
issues-exit-code是顶层字段,和run、linters平级,不能缩进到run:下面 - 设为
1表示“只要任意 linter 报出至少 1 条 issue,就退出 1”;设为0则永远返回 0(调试时可用) - 若想更精细控制(比如只对
staticcheck严格,govet宽松),得配合issues.max-issues-per-linter+issues-exit-code组合使用 - CI 中建议固定写死:
issues-exit-code: 1,避免依赖环境变量或 shell 状态
常见误配导致 exit-code 失效
配置写了却没生效?八成掉进了这些坑:
立即学习“go语言免费学习笔记(深入)”;
- 把
issues-exit-code: 1错写在run:或linters-settings:下面——YAML 缩进错一层,整个字段被忽略 - 文件名是
golangci.yml(缺点)或.golangci.yaml(后缀错)→ 工具压根不读配置,退回到默认 0 退出 - CI 脚本里用了
--fast模式 → 它会跳过所有 slow linter(包括staticcheck),自然也没 issue 可触发 exit-code - 配置里
linters.disable把staticcheck关了,只剩govet和errcheck→ 这俩默认不报 SA 类问题,根本凑不够触发条件
最常被忽略的一点:exit-code 生效前提是 issue 真的被生成出来。如果 staticcheck 因 GO111MODULE=off 解析失败、或 go.mod 路径不对导致类型信息缺失,它连 warning 都不报,更别说触发退出码了。


















