vxcontrol/pentagi · error · Retryable

failed to do request: %v

Error message

failed to do request: %v

What it means

traversaal.search returns a Retryable error 'failed to do request: %v' when client.Do(req) fails — the HTTP round trip itself did not complete: DNS failure, connection refused/reset, TLS handshake error, or context cancellation/timeout. It is classified Retryable so the orchestrator may retry or fall back to another engine.

Source

Thrown at backend/pkg/tools/searchers/traversaal.go:97

	}{
		Query: query,
	})
	if err != nil {
		return "", Fatal(fmt.Errorf("failed to marshal request body: %v", err))
	}

	req, err := http.NewRequest(http.MethodPost, traversaalURL, 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")
	req.Header.Set("x-api-key", t.apiKey())

	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(resp)
}

func (t *traversaal) parseHTTPResponse(resp *http.Response) (string, error) {
	if resp.StatusCode != http.StatusOK {
		err := fmt.Errorf("unexpected status code: %d", resp.StatusCode)
		if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {
			return "", Retryable(err, 0)
		}
		return "", Fatal(err)
	}
	var respBody struct {
		Data traversaalSearchResult `json:"data"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check network egress/DNS from the backend container (e.g. curl the Traversaal endpoint from inside).
  2. Inspect the wrapped error: 'context deadline exceeded' means raise the caller timeout; 'connection refused' means egress/proxy blocking.
  3. Configure a valid HTTP(S) proxy or add the proxy CA to the trust store if traffic is intercepted.
  4. Rely on Retryable classification to fall back to another engine in the web_search fallbackStrategy.

Example fix

// before: unbounded caller context
ctx := context.Background()
// after: bounded, cancellation-aware context
ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
Defensive patterns

Strategy: retry

Validate before calling

if err := ctx.Err(); err != nil {
    return fmt.Errorf("context already done, skipping search: %w", err)
}

Type guard

func isRetryable(err error) bool {
    var r *searchers.RetryableError
    return errors.As(err, &r)
}

Try / catch

result, err := traversaalSearcher.Handle(ctx, req)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        return "", fmt.Errorf("traversaal timed out; raise caller timeout")
    }
    if isRetryable(err) {
        return fallbackEngine.Handle(ctx, req)
    }
    return "", err
}

Prevention

When it happens

Trigger: client.Do(req) returns err in search() — network unreachable, DNS resolution failure for the Traversaal host, TLS errors, or the request context (ctx) was canceled/timed out by the caller.

Common situations: No outbound internet/DNS in the Docker container; corporate proxy blocking api.traversaal.ai; ctx deadline exceeded under slow agent pipelines; TLS interception with unknown CA.

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


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/9db0e43d39e64717. Report an issue: GitHub.