Tencent/WeKnora · error

failed to perform request: %w

Error message

failed to perform request: %w

What it means

The HTTP client failed to execute the DuckDuckGo HTML search request in searchHTML (transport-level failure), wrapped as "failed to perform request". No response was received, so this is a connection/TLS/DNS/context problem rather than a bad status.

Source

Thrown at internal/infrastructure/web_search/duckduckgo.go:95

	reqURL := baseURL + "?" + params.Encode()
	req, err := http.NewRequestWithContext(ctx, "GET", reqURL, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set(
		"User-Agent",
		"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
	)

	curlCommand := fmt.Sprintf(
		"curl -X GET '%s' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'",
		req.URL.String(),
	)
	logger.Infof(ctx, "Curl of request: %s", secutils.SanitizeForLog(curlCommand))

	resp, err := p.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to perform request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
		return nil, fmt.Errorf("duckduckgo HTML returned status %d", resp.StatusCode)
	}

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to parse HTML: %w", err)
	}

	results := make([]*types.WebSearchResult, 0, maxResults)
	doc.Find(".web-result").Each(func(i int, s *goquery.Selection) {
		if len(results) >= maxResults {
			return
		}
		titleNode := s.Find(".result__a")

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Check the wrapped error class: context.DeadlineExceeded -> increase timeout or retry; connection refused -> verify network/proxy.
  2. Confirm outbound HTTPS to html.duckduckgo.com is allowed from your host.
  3. Configure an HTTP proxy on p.client if running behind corporate egress.
  4. Add retry with backoff for transient transport errors.
Defensive patterns

Strategy: retry

Validate before calling

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// pass ctx into the search call

Type guard

func isTransportErr(err error) bool {
    if err == nil { return false }
    var ne net.Error
    return errors.As(err, &ne) || strings.Contains(err.Error(), "failed to perform request")
}

Try / catch

var lastErr error
for attempt := 0; attempt < 3; attempt++ {
    results, err := ddg.Search(ctx, query, 10, false)
    if err == nil { return results, nil }
    lastErr = err
    if strings.Contains(err.Error(), "failed to perform request") {
        time.Sleep(backoff(attempt)) // transport error: retry
        continue
    }
    break // non-transport: don't retry
}

Prevention

When it happens

Trigger: client.Do(req) returns an error: DNS resolution failure, connection refused/timeout, TLS handshake failure, or ctx cancellation mid-request.

Common situations: No internet access or blocked egress (firewall, sandboxed CI); DuckDuckGo refusing datacenter IPs at TLS level; requests without a timeout hanging until the context deadline.

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 Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/2f7a4e0ed2451716. Report an issue: GitHub.