Errors Direct Comparison

ID

go.errors_direct_comparison

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Go

Tags

reliability, suspicious

Description

Reports a direct == / != comparison between a local error variable and an error sentinel — err == ErrNotFound. The idiomatic test is errors.Is(err, ErrNotFound).

Rationale

Comparing errors by identity breaks the moment an error is wrapped with fmt.Errorf("…​: %w", err): the wrapped value is no longer == the sentinel even though it still is that error. errors.Is unwraps the chain before comparing, so it keeps working as errors are wrapped and re-wrapped across call boundaries.

To stay free of false positives the rule relies on the universal Go naming conventions: one operand must be a bare identifier named err, and the other a bare identifier that looks like an exported sentinel (Err followed by an upper-case letter). Package-qualified sentinels such as io.EOF are out of scope, and a nil comparison is never flagged.

if err == ErrNotFound { ... }      // FLAW — use errors.Is(err, ErrNotFound)

if errors.Is(err, ErrNotFound) {}  // OK
if err == nil { ... }              // OK — nil check
if err == io.EOF { ... }           // OK — package-qualified sentinel, out of scope

Remediation

Replace the identity comparison with errors.Is(err, sentinel) (and !errors.Is(…​) for the != form) so that wrapped errors are matched too.