Summary
The newly added closeerrorunchecked linter (pkg/linters/closeerrorunchecked/closeerrorunchecked.go, PR #64310, added 2026-09-29 as the 74th registered analyzer) does bare *ast.CallExpr type assertions on the right-hand side of blank-identifier assignments with no ParenExpr unwrapping first. This is the well established paren_unwrap_gap class already filed in this repository against nilctxpassed, errstringmatch, sprintfbool, tolowerequalfold, timenowsub, httpstatuscode, seenmapbool, and the shared astutil.StringLitValue/IsStringLiteral helpers - closeerrorunchecked reproduces the identical gap on day one.
Evidence
In analyzeAssignStmt (closeerrorunchecked.go lines 59-63, Pattern 1 single blank assign) and lines 83-87 (Pattern 2 multi-return blank assign), the code does a direct call, ok := rhs.(*ast.CallExpr) assertion with no astutil.UnwrapParenExpr(rhs) call first. This is a direct sibling of the correctly guarded idiom already used elsewhere in this codebase, for example walkfuncerrshadow, mapdeletecheck, packagelevelmutableslicemap, and typeassertionokdiscarded all unwrap parens before asserting.
Impact
A statement such as _ = (f.Close()) or a multi-return form such as value, _ := (closer.Close()) is legal Go, since parentheses around an assignment right-hand-side expression are always permitted, and silently discards the Close error exactly like the flagged _ = f.Close() case already covered in the linters own testdata (BadBlankAssignClose). It escapes detection purely because of the extra parens. closeerrorunchecked is not yet CI-enforced (absent from .github/workflows/cgo.yml LINTER_FLAGS as of this run), so the gap is latent rather than actively missing CI findings today, but it will start missing real cases the moment the linter is enforced, since zero paren-wrapped fixtures exist in testdata/src/closeerrorunchecked.
Recommendation
Wrap both call, ok := rhs.(*ast.CallExpr) assertions in analyzeAssignStmt with astutil.UnwrapParenExpr(rhs) first, matching the fix idiom already established elsewhere in this codebase. Add parenthesized-call fixtures to testdata/src/closeerrorunchecked/closeerrorunchecked.go covering both the single blank-assign and multi-return forms.
Validation checklist
- Add a BadParenWrappedClose case with _ = (f.Close()) expecting a diagnostic
- Add a BadParenWrappedMultiReturnClose case with value, _ := (closer.Close()) expecting a diagnostic
- Confirm GoodDeferClose and the other clean cases remain unflagged
- Run go test ./pkg/linters/closeerrorunchecked/...
Effort: small, a two line fix plus two test fixtures.
Generated by 🤖 Sergo - Serena Go Expert · claude · agent · 258.2 AIC · ⌖ 4.64 AIC · ⊞ 4.9K · ◷
Summary
The newly added closeerrorunchecked linter (pkg/linters/closeerrorunchecked/closeerrorunchecked.go, PR #64310, added 2026-09-29 as the 74th registered analyzer) does bare *ast.CallExpr type assertions on the right-hand side of blank-identifier assignments with no ParenExpr unwrapping first. This is the well established paren_unwrap_gap class already filed in this repository against nilctxpassed, errstringmatch, sprintfbool, tolowerequalfold, timenowsub, httpstatuscode, seenmapbool, and the shared astutil.StringLitValue/IsStringLiteral helpers - closeerrorunchecked reproduces the identical gap on day one.
Evidence
In analyzeAssignStmt (closeerrorunchecked.go lines 59-63, Pattern 1 single blank assign) and lines 83-87 (Pattern 2 multi-return blank assign), the code does a direct call, ok := rhs.(*ast.CallExpr) assertion with no astutil.UnwrapParenExpr(rhs) call first. This is a direct sibling of the correctly guarded idiom already used elsewhere in this codebase, for example walkfuncerrshadow, mapdeletecheck, packagelevelmutableslicemap, and typeassertionokdiscarded all unwrap parens before asserting.
Impact
A statement such as _ = (f.Close()) or a multi-return form such as value, _ := (closer.Close()) is legal Go, since parentheses around an assignment right-hand-side expression are always permitted, and silently discards the Close error exactly like the flagged _ = f.Close() case already covered in the linters own testdata (BadBlankAssignClose). It escapes detection purely because of the extra parens. closeerrorunchecked is not yet CI-enforced (absent from .github/workflows/cgo.yml LINTER_FLAGS as of this run), so the gap is latent rather than actively missing CI findings today, but it will start missing real cases the moment the linter is enforced, since zero paren-wrapped fixtures exist in testdata/src/closeerrorunchecked.
Recommendation
Wrap both call, ok := rhs.(*ast.CallExpr) assertions in analyzeAssignStmt with astutil.UnwrapParenExpr(rhs) first, matching the fix idiom already established elsewhere in this codebase. Add parenthesized-call fixtures to testdata/src/closeerrorunchecked/closeerrorunchecked.go covering both the single blank-assign and multi-return forms.
Validation checklist
Effort: small, a two line fix plus two test fixtures.