vxcontrol/pentagi · warning · RetryableError
%s (HTTP %d)
Error message
%s (HTTP %d)
What it means
ClassifyHTTPStatus returns a RetryableError for any status >= 500, since an upstream/server-side problem may clear on a retry of the same engine. The message embeds the caller-provided text plus the actual HTTP status code.
Source
Thrown at backend/pkg/tools/searchers/errors.go:59
// Fatal wraps err as a FatalError.
func Fatal(err error) error {
return &FatalError{Err: err}
}
// ClassifyHTTPStatus maps a non-2xx HTTP status to the right typed error so every
// engine classifies identically. The engine supplies a human-readable message; the
// retry/fatal decision is centralized here.
//
// 429 -> RetryableError (rate limited; back off and retry the same engine)
// 5xx -> RetryableError (upstream problem; may clear on retry)
// 4xx/other -> FatalError (auth/bad-request/etc.; retrying the same engine is pointless)
func ClassifyHTTPStatus(status int, msg string) error {
switch {
case status == http.StatusTooManyRequests:
return Retryable(fmt.Errorf("%s (HTTP 429)", msg), 0)
case status >= 500:
return Retryable(fmt.Errorf("%s (HTTP %d)", msg, status), 0)
default:
return Fatal(fmt.Errorf("%s (HTTP %d)", msg, status))
}
}
// IsRetryable reports whether err (or anything it wraps) is a RetryableError.
func IsRetryable(err error) bool {
var t *RetryableError
return errors.As(err, &t)
}
// IsFatal reports whether err (or anything it wraps) is a FatalError.
func IsFatal(err error) bool {
var t *FatalError
return errors.As(err, &t)
}
View on GitHub (pinned to ea665308ba)
Solutions
- Retry the same engine; the typed error signals the transient nature.
- Check the engine provider's status page for an outage.
- If 5xx persists, switch to a fallback engine via the fallbackStrategy chain.
- Log the status code and msg to identify which upstream endpoint is failing.
Example fix
// before
return classifyGoogleError(status, body)
// after (caller side)
if err := ...; searchers.IsRetryable(err) { retryOrFallback(err) } Defensive patterns
Strategy: retry
Validate before calling
// health-check the engine before batch runs
resp, err := http.Get(engineBaseURL + "/healthz")
if err != nil || resp.StatusCode >= 500 { skipEngine() } Type guard
func isServerError(err error) bool {
return searchers.IsRetryable(err) && !strings.Contains(err.Error(), "HTTP 429")
} Try / catch
err := searcher.Handle(ctx, q)
if err != nil && searchers.IsRetryable(err) {
if attempt < maxAttempts { retryWithBackoff() } else { useFallbackEngine() }
} Prevention
- Subscribe to engine provider status pages.
- Cap retries with exponential backoff, then fall back.
- Keep a second engine configured for every mode.
- Log status codes to spot persistent upstream degradation.
When it happens
Trigger: Upstream search engine returns 500, 502, 503 or similar while ClassifyHTTPStatus is called from an engine adapter (e.g. classifyGoogleError).
Common situations: Engine provider outage or partial degradation, gateway timeouts behind the search API, transient 502s from a CDN in front of the engine.
Related errors
- %s (HTTP 429)
- there had a problem with our server. try again later
- failed to do request: %w
- failed to do request: %v
- there are requesting too many results
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/43ec57ed6a966313.
Report an issue: GitHub.