goland默认不标出未处理错误,需启用“unhandled error result”检查项并在settings→editor→inspections→go中勾选,它对os.open等函数及write等方法调用生效,但不覆盖if err != nil块内语句,且可能误判log.printf等场景。

GoLand 里默认不标出未处理错误,得靠检查器开火
GoLand 本身不会像编译器那样报 error 未检查的错误——Go 语言允许你忽略返回的 error,IDE 就不会强制拦截。但你可以启用内置的静态检查:GoLand 的 Unhandled error result 检查项,它会在调用返回 error 的函数后、没做任何处理(比如赋值给变量、判空、传给 _)时标黄提示。
开启路径:Settings → Editor → Inspections → Go → Unhandled error result,勾选并确认作用域(推荐选 “All places”)。注意:该检查仅对函数调用生效,不覆盖 if err != nil 块内部的后续语句。
- 常见误判场景:调用
log.Printf或fmt.Println后直接丢弃error(如fmt.Println(f.Write([]byte{}))),会被标为未处理——其实你本意就是“只打印不处理”,这时应显式写成_ = f.Write(...) - 该检查对方法调用(如
os.File.Write)和函数调用(如os.Open)都有效,但对类型断言、通道接收等不返回error的表达式无效 - 若项目用了
golang.org/x/exp/errors或自定义错误包装器,检查器可能无法识别,需依赖errors.Is/errors.As的显式判断才能绕过警告
用 go vet -shadow 和自定义分析器补漏
go vet 自带的 -shadow 不管错误处理,但它能揪出因变量遮蔽导致的 err 覆盖问题(比如外层 err 被内层 if err := xxx(); err != nil 遮住,结果忘了处理新 err)。真正补漏的是 go vet -printfuncs=Errorf,Warnf 这类定制,但更实用的是第三方分析器:
GoLand 2026.1.1 是 2026.1 发布后的首个维护修正版本,适合已经开始体验 2026.1 新功能并希望同步补丁的开发者。它更适合用于入门项目、现有项目迁移测试和 IDE 行为验证。
-
errcheck是最直接的工具:运行errcheck ./...会列出所有未检查的error返回值;在 GoLand 中可配置为外部工具,绑定快捷键一键扫描 -
staticcheck的SA1019(过时 API)和SA1005(未检查error)更严格,能发现io.Copy后没检查返回值、或defer f.Close()里没处理f.Close()的error - 注意:这些命令行工具不感知 GoLand 的代码折叠或注释掉的代码块,扫描的是实际编译路径下的文件,所以要确保
go.mod正确且GOOS/GOARCH环境匹配
为什么 if err != nil 写了还被标红?可能是作用域或赋值问题
常见假阳性:你写了 if err != nil { return err },但 GoLand 仍标黄调用处——大概率是 err 变量没被声明或不在同一作用域。典型情况包括:
- 忘记加
err接收:写成json.Unmarshal(data, &v)而非err := json.Unmarshal(data, &v)或_, err := json.Unmarshal(...) - 在
for或if内部声明err,但检查器看到的是外部作用域无err变量,于是认为“调用结果被完全丢弃” - 使用了
:=但左侧已有同名变量(如外层已定义err),此时 Go 要求至少一个新变量,否则编译失败;而 GoLand 的检查器可能提前触发,误判为未接收 - 调用链中某步返回的是
(int, error),你只接了_, err := fn(),但检查器期望你至少用上第一个返回值(哪怕只是_),否则仍报未处理
别指望 IDE 100% 找全,关键逻辑必须人工走读
GoLand 的检查器对嵌套调用、接口方法、反射调用、生成代码(如 protobuf 的 Unmarshal)支持有限;errcheck 也跳过被 //nolint:errcheck 注释标记的行。真正高风险的位置——比如文件写入、网络请求、数据库事务提交——即使工具没报,也要人工确认是否做了错误分支处理、是否记录日志、是否回滚状态。
最容易被忽略的是 defer 里的资源关闭操作:你写了 defer f.Close(),但 f.Close() 本身返回 error,而 defer 不捕获也不传播这个 error,它就静默消失了。这种地方必须显式检查,比如 defer func() { _ = f.Close() }() 或单独调用并处理。










