Tencent/WeKnora · error

duckduckgo API search failed: %w

Error message

duckduckgo API search failed: %w

What it means

This is the DuckDuckGo Instant Answer API fallback failure: the HTML search failed and searchAPI returned an error, so Search wraps the API error as "duckduckgo API search failed". Both the HTML scrape and the API fallback failed.

Source

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

	includeDate bool,
) ([]*types.WebSearchResult, error) {
	if maxResults <= 0 {
		maxResults = 5
	}
	// Try HTML scraping first (more reliable for general results)
	htmlResults, err := p.searchHTML(ctx, query, maxResults)
	if err == nil && len(htmlResults) > 0 {
		return htmlResults, nil
	}
	// Fallback to Instant Answer API
	apiResults, apiErr := p.searchAPI(ctx, query, maxResults)
	if apiErr == nil && len(apiResults) > 0 {
		return apiResults, nil
	}
	if err != nil {
		return nil, fmt.Errorf("duckduckgo HTML search failed: %w", err)
	}
	return nil, fmt.Errorf("duckduckgo API search failed: %w", apiErr)
}

// searchHTML performs a web search using DuckDuckGo HTML endpoint
func (p *DuckDuckGoProvider) searchHTML(
	ctx context.Context,
	query string,
	maxResults int,
) ([]*types.WebSearchResult, error) {
	baseURL := "https://html.duckduckgo.com/html/"
	params := url.Values{}
	params.Set("q", query)
	params.Set("kl", "cn-zh")

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

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped apiErr for the underlying network/HTTP cause.
  2. Verify outbound HTTPS connectivity to duckduckgo.com and api.duckduckgo.com.
  3. Implement exponential backoff and retry for transient network failures.
  4. Configure an alternate provider (e.g. Bing/Brave/Serper) as a final fallback.
Defensive patterns

Strategy: fallback

Validate before calling

conn, err := net.DialTimeout("tcp", "duckduckgo.com:443", 3*time.Second)
if err != nil {
    return errors.New("no connectivity to duckduckgo; check network")
}
conn.Close()

Type guard

func isDDGAPIFailure(err error) bool {
    return err != nil && strings.Contains(err.Error(), "duckduckgo API search failed")
}

Try / catch

results, err := ddg.Search(ctx, query, 10, false)
if err != nil {
    if isDDGAPIFailure(err) || isDDGHTMLFailure(err) {
        results, err = altProvider.Search(ctx, query, 10, false)
    }
}

Prevention

When it happens

Trigger: searchHTML returned an error, and searchAPI also returned an error (apiErr != nil), so control reaches the second fmt.Errorf in Search.

Common situations: Total loss of network connectivity; DNS failures; the Instant Answer API returning 403/rate limits; queries for which the API errors instead of returning empty results.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/b602785f3481e2e3. Report an issue: GitHub.