{"record":{"id":"b602785f3481e2e3","repo":"Tencent/WeKnora","slug":"duckduckgo-api-search-failed-w","errorCode":null,"errorMessage":"duckduckgo API search failed: %w","messagePattern":"duckduckgo API search failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/duckduckgo.go","lineNumber":63,"sourceCode":"\tincludeDate bool,\n) ([]*types.WebSearchResult, error) {\n\tif maxResults <= 0 {\n\t\tmaxResults = 5\n\t}\n\t// Try HTML scraping first (more reliable for general results)\n\thtmlResults, err := p.searchHTML(ctx, query, maxResults)\n\tif err == nil && len(htmlResults) > 0 {\n\t\treturn htmlResults, nil\n\t}\n\t// Fallback to Instant Answer API\n\tapiResults, apiErr := p.searchAPI(ctx, query, maxResults)\n\tif apiErr == nil && len(apiResults) > 0 {\n\t\treturn apiResults, nil\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"duckduckgo HTML search failed: %w\", err)\n\t}\n\treturn nil, fmt.Errorf(\"duckduckgo API search failed: %w\", apiErr)\n}\n\n// searchHTML performs a web search using DuckDuckGo HTML endpoint\nfunc (p *DuckDuckGoProvider) searchHTML(\n\tctx context.Context,\n\tquery string,\n\tmaxResults int,\n) ([]*types.WebSearchResult, error) {\n\tbaseURL := \"https://html.duckduckgo.com/html/\"\n\tparams := url.Values{}\n\tparams.Set(\"q\", query)\n\tparams.Set(\"kl\", \"cn-zh\")\n\n\treqURL := baseURL + \"?\" + params.Encode()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", reqURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create request: %w\", err)\n\t}","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/duckduckgo.go#L45-L81","documentation":"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.","triggerScenarios":"searchHTML returned an error, and searchAPI also returned an error (apiErr != nil), so control reaches the second fmt.Errorf in Search.","commonSituations":"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.","solutions":["Inspect the wrapped apiErr for the underlying network/HTTP cause.","Verify outbound HTTPS connectivity to duckduckgo.com and api.duckduckgo.com.","Implement exponential backoff and retry for transient network failures.","Configure an alternate provider (e.g. Bing/Brave/Serper) as a final fallback."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"conn, err := net.DialTimeout(\"tcp\", \"duckduckgo.com:443\", 3*time.Second)\nif err != nil {\n    return errors.New(\"no connectivity to duckduckgo; check network\")\n}\nconn.Close()","typeGuard":"func isDDGAPIFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"duckduckgo API search failed\")\n}","tryCatchPattern":"results, err := ddg.Search(ctx, query, 10, false)\nif err != nil {\n    if isDDGAPIFailure(err) || isDDGHTMLFailure(err) {\n        results, err = altProvider.Search(ctx, query, 10, false)\n    }\n}","preventionTips":["Check outbound network/DNS in the deployment environment (CI containers often block egress).","Set explicit HTTP client timeouts so failures surface fast.","Maintain a provider priority list with automatic failover."],"tags":["web-search","network","api","go"],"backgroundTag":"upstream-api-request-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}