Summary
A isNotFoundError(errMsg string) bool helper exists at pkg/parser/remote_fetch.go:610 and centralizes the gh/HTTP 404 detection pattern (404 OR not found, case-insensitive). However, it lives in pkg/parser as unexported, so several pkg/cli call sites reimplement the same substring matching inline. The duplicate sites have already drifted: each picks a different subset of the canonical signals.
Existing helper (unexported, wrong package)
// pkg/parser/remote_fetch.go:610
func isNotFoundError(errMsg string) bool {
lowerMsg := strings.ToLower(errMsg)
return strings.Contains(lowerMsg, "404") || strings.Contains(lowerMsg, "not found")
}
Duplicate call sites in pkg/cli
| File:Line |
Current code |
Signals matched |
pkg/cli/audit.go:1037-1042 |
5 separate strings.Contains calls ("Not Found", "404", "not found", "Could not resolve", err.Error() "404") |
Superset — could feed back into helper |
pkg/cli/outcome_eval_comment.go:34 |
strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "Not Found") |
Case-sensitive, misses lowercase not found |
pkg/cli/gateway_logs_mcp.go:28 |
strings.Contains(err.Error(), "not found") |
Misses 404 literal |
pkg/cli/logs_download.go:316 |
strings.Contains(string(output), "not found") || strings.Contains(err.Error(), "410") |
Mixes 404+410, lowercase only |
Why
- Helper-underadoption failure mode, recurring theme across Sergo Runs 8–11 (HTTP timeout, file mode constants, GetWorkflowDir, etc.).
- The duplicates already disagree on what counts as "not found":
outcome_eval_comment.go:34 is case-sensitive, while remote_fetch.go:610 lower-cases first.
audit.go:1037 adds "Could not resolve" (DNS-failure phrasing from git clone).
gateway_logs_mcp.go:28 skips the bare "404" substring entirely.
- Single source of truth makes evolution (e.g. matching on
*ghapi.HTTPError once gh CLI / go-gh exposes structured errors) a one-line change.
Suggested fix
- Move the helper to a shared location — options:
- Export it:
parser.IsNotFoundError(err error) bool (still in pkg/parser).
- Or create
pkg/ghapi/errors.go (or pkg/errorutil) and put both IsNotFoundError and an exported sibling of isPermissionError (#aw_sgcr1) there. Recommended — avoids pkg/cli and pkg/parser importing each other.
- Change the signature to
func IsNotFoundError(err error) bool (and ignore nil err). The current string parameter forces callers to call err.Error() and loses wrapping.
- Replace the four duplicate sites to call it.
- Make the helper case-insensitive (lower-case once) — the canonical implementation in
remote_fetch.go:610 already does this; the divergent outcome_eval_comment.go site is silently buggier today.
Validation
Severity
Medium. outcome_eval_comment.go is silently missing lower-cased "not found" matches today — a small but real false-negative footprint.
Context
Found by Sergo Run 12 — helper-adoption follow-up + error-comparison audit. Run §25981825933. Companion issue: helper-underadoption pair with isPermissionError consolidation.
Generated by 🤖 Sergo - Serena Go Expert · ● 23.5M · ◷
Summary
A
isNotFoundError(errMsg string) boolhelper exists atpkg/parser/remote_fetch.go:610and centralizes the gh/HTTP 404 detection pattern (404ORnot found, case-insensitive). However, it lives inpkg/parseras unexported, so severalpkg/clicall sites reimplement the same substring matching inline. The duplicate sites have already drifted: each picks a different subset of the canonical signals.Existing helper (unexported, wrong package)
Duplicate call sites in pkg/cli
pkg/cli/audit.go:1037-1042strings.Containscalls ("Not Found","404","not found","Could not resolve",err.Error()"404")pkg/cli/outcome_eval_comment.go:34strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "Not Found")not foundpkg/cli/gateway_logs_mcp.go:28strings.Contains(err.Error(), "not found")404literalpkg/cli/logs_download.go:316strings.Contains(string(output), "not found") || strings.Contains(err.Error(), "410")Why
outcome_eval_comment.go:34is case-sensitive, whileremote_fetch.go:610lower-cases first.audit.go:1037adds"Could not resolve"(DNS-failure phrasing fromgit clone).gateway_logs_mcp.go:28skips the bare"404"substring entirely.*ghapi.HTTPErroronce gh CLI / go-gh exposes structured errors) a one-line change.Suggested fix
parser.IsNotFoundError(err error) bool(still inpkg/parser).pkg/ghapi/errors.go(orpkg/errorutil) and put bothIsNotFoundErrorand an exported sibling ofisPermissionError(#aw_sgcr1) there. Recommended — avoidspkg/cliandpkg/parserimporting each other.func IsNotFoundError(err error) bool(and ignorenil err). The currentstringparameter forces callers to callerr.Error()and loses wrapping.remote_fetch.go:610already does this; the divergentoutcome_eval_comment.gosite is silently buggier today.Validation
go test ./pkg/cli/... ./pkg/parser/...passes.strings.Contains(err.Error(), "404")or"Not Found"outside the helper.Severity
Medium.
outcome_eval_comment.gois silently missing lower-cased "not found" matches today — a small but real false-negative footprint.Context
Found by Sergo Run 12 — helper-adoption follow-up + error-comparison audit. Run §25981825933. Companion issue: helper-underadoption pair with
isPermissionErrorconsolidation.