Skip to content

errstringmatch coverage gap: only strings.Contains(err.Error(), ...) is flagged — HasPrefix/HasSuffix/EqualFold/Index on err.Err [Content truncated due to length] #40244

Description

@github-actions

Summary

The errstringmatch linter (pkg/linters/errstringmatch/errstringmatch.go) exists to flag brittle substring matching on error messages and steer callers toward errors.Is/errors.As/sentinel errors. Its own doc string says it reports calls that "perform brittle substring matching on error messages". But the implementation only matches strings.Contains (isStringsContains, line 76-86). The same anti-pattern expressed with other strings functions on err.Error() is just as brittle and is silently missed.

The gap (pattern-set too narrow)

The nodeFilter and pkg-identity logic are fine; the matched function set is the problem. Equally brittle, equally unflagged:

strings.HasPrefix(err.Error(), "connection refused")
strings.HasSuffix(err.Error(), "not found")
strings.EqualFold(err.Error(), "timeout")
strings.Index(err.Error(), "denied") >= 0
strings.Contains(strings.ToLower(err.Error()), "...")  // nested

Each matches an error by its human-readable message text, which breaks when the wrapped/underlying error wording changes — exactly the failure errstringmatch is meant to prevent. Only Contains is caught today.

Distinction from the package-identity issue

This is a different class from the ident.Name == "strings" syntactic-identity gap (tracked separately): that one is about how the strings package is resolved; this one is about which strings functions count as brittle error matching. Both touch errstringmatch.go but are orthogonal and should be fixed independently.

Current impact

Latent: a scan of pkg/ finds 0 production sites using HasPrefix/HasSuffix/EqualFold/Index/Compare on err.Error() today (12 strings.Contains(err.Error(), ...) sites exist and are handled). So this is a false-negative hardening finding — closing it before such code lands keeps the CI-enforced guard complete rather than fixing a present violation.

Recommendation

Generalize isStringsContains to an isBrittleErrStringFunc that recognizes the brittle strings matching functions, keeping the existing err.Error() + string-literal argument guards. Suggested set: Contains, HasPrefix, HasSuffix, EqualFold, Index, LastIndex, Compare. Note that HasPrefix/HasSuffix/EqualFold take the searched string as the first arg and the literal as the second — same shape as Contains (outer.Args[0] = err.Error(), outer.Args[1] = literal), so the existing arg checks (lines 56-63) transfer directly. Index/Compare differ only in that the brittle comparison is on the result; matching the call itself is still the right signal.

Tune the diagnostic message to name the matched function, e.g. "avoid strings.%s(err.Error(), ...) — use errors.Is, errors.As, or a sentinel error instead".

Validation checklist

  • testdata: add positive cases for HasPrefix/HasSuffix/EqualFold/Index on err.Error() with a string literal — confirm flagged.
  • testdata: keep a negative case where the first arg is NOT err.Error() (e.g. a plain string) — confirm not flagged (no over-broad matching of ordinary strings.HasPrefix).
  • Existing strings.Contains(err.Error(), ...) expectations unchanged.
  • go test ./pkg/linters/errstringmatch/... green; CI linter pass over pkg/ produces no new diagnostics (expected, given 0 latent sites).

Effort

Small — widen one predicate to a small allow-list of function names plus testdata; existing argument/pkg-identity guards reused. Single PR. Coordinate the second-arg shape only if Index/Compare are included.

Related

Separate from the package-identity migration that also touches errstringmatch.go:85. Same linter, orthogonal precision dimension.

Generated by 🤖 Sergo - Serena Go Expert · 339.2 AIC · ⌖ 14.7 AIC · ⊞ 5.8K ·

  • expires on Jun 25, 2026, 9:36 PM UTC-08:00

Metadata

Metadata

Labels

cookieIssue Monster Loves Cookies!sergo

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions