vxcontrol/pentagi · error · Retryable
failed to do request: %v
Error message
failed to do request: %v
What it means
Thrown in tavily.search when the HTTP POST to https://api.tavily.com/search fails at the transport level (client.Do returned an error), before any HTTP status is available. The searcher wraps the underlying net/http error as Retryable(err, 0) so the web_search orchestrator may retry with fallback engines. It means DNS failure, TCP connect failure, TLS failure, request cancellation (context), or a proxy problem — not a Tavily API rejection.
Source
Thrown at backend/pkg/tools/searchers/tavily.go:134
IncludeRawContent: true,
MaxResults: maxResults,
}
reqBody, err := json.Marshal(reqPayload)
if err != nil {
return "", Fatal(fmt.Errorf("failed to marshal request body: %v", err))
}
req, err := http.NewRequest(http.MethodPost, tavilyURL, bytes.NewBuffer(reqBody))
if err != nil {
return "", Fatal(fmt.Errorf("failed to build request: %v", err))
}
req = req.WithContext(ctx)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return "", Retryable(fmt.Errorf("failed to do request: %v", err), 0)
}
defer resp.Body.Close()
return t.parseHTTPResponse(ctx, resp)
}
func (t *tavily) parseHTTPResponse(ctx context.Context, resp *http.Response) (string, error) {
switch resp.StatusCode {
case http.StatusOK:
var respBody tavilySearchResult
if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
return "", Fatal(fmt.Errorf("failed to decode response body: %v", err))
}
return t.buildTavilyResult(ctx, &respBody), nil
case http.StatusBadRequest:
return "", Fatal(fmt.Errorf("request is invalid"))
case http.StatusUnauthorized:
return "", Fatal(fmt.Errorf("API key is wrong"))View on GitHub (pinned to ea665308ba)
Solutions
- Check basic connectivity from the same container: curl -v https://api.tavily.com/search — fix DNS/firewall/proxy if it fails.
- If behind a proxy, verify HTTPS_PROXY/HTTP_PROXY env vars and that the proxy CA cert is trusted by the container.
- If the context deadline is the cause, increase the caller's timeout for the web_search tool.
- Check status.tavily.com or retry later if Tavily itself is down; ensure a fallback engine (e.g. DuckDuckGo) is configured in the web_search fallback chain.
- Since the error is Retryable, verify the orchestrator retry policy is enabled so transient blips self-heal.
Example fix
// before: cryptic transport failure inside the sandbox
client, err := system.GetHTTPClient(t.cfg)
// after: fail fast with a clear config check and honor ctx deadline
if t.cfg.TavilyAPIKey == "" { return "", ErrNotConfigured }
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
resp, err := client.Do(req) Defensive patterns
Strategy: retry
Validate before calling
// check egress before calling the engine
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.tavily.com", nil)
if _, err := http.DefaultClient.Do(req); err != nil {
return fmt.Errorf("no egress to api.tavily.com: %w", err)
} Type guard
func isRetryableTransportErr(err error) bool {
return errors.Is(err, context.DeadlineExceeded) ||
errors.Is(err, context.Canceled) ||
errors.Is(err, syscall.ECONNREFUSED) ||
errors.Is(err, syscall.EHOSTUNREACH) ||
errors.Is(err, io.EOF)
} Try / catch
result, err := searcher.Handle(ctx, req)
if err != nil {
var rerr *RetryableError
if errors.As(err, &rerr) {
// back off and retry, then fall back to another engine
}
return err
} Prevention
- Smoke-test egress (curl https://api.tavily.com) in the container image or entrypoint before enabling the engine.
- Set an explicit request timeout instead of inheriting an unbounded caller context.
- Validate proxy env vars and CA certs whenever the deployment changes.
- Always configure at least one fallback engine in the web_search fallback chain.
When it happens
Trigger: client.Do(req) in search (tavily.go:132) returns err: network unreachable, DNS resolution failure of api.tavily.com, TLS handshake failure, proxy misconfiguration (system.GetHTTPClient with proxy settings), or ctx cancelled/timed out mid-request.
Common situations: No internet access or DNS failure in the Docker sandbox; corporate proxy or self-signed MITM cert (HTTPS_PROXY / custom CA) misconfigured; Tavily outage or regional block; request deadline exceeded because the search took too long; IPv6-only environment that cannot reach the API.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- request to Sploitus failed: %w
- failed to put input for subtask %d: %w
- failed to perform agent chain for subtask %d: %w
- temporal window search failed: %w
- entity relationships search failed: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/8de6d2d5b30b5a75.
Report an issue: GitHub.