{"record":{"id":"30ba18622135a2d2","repo":"vxcontrol/pentagi","slug":"duckduckgo-search-failed-w","errorCode":null,"errorMessage":"duckduckgo search failed: %w","messagePattern":"duckduckgo search failed: %w","errorType":"exception","errorClass":"FatalError","httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/searchers/duckduckgo.go","lineNumber":126,"sourceCode":"\t\tobservation.Event(\n\t\t\tlangfuse.WithEventName(\"search engine error\"),\n\t\t\tlangfuse.WithEventInput(req.Query),\n\t\t\tlangfuse.WithEventStatus(err.Error()),\n\t\t\tlangfuse.WithEventLevel(langfuse.ObservationLevelWarning),\n\t\t\tlangfuse.WithEventMetadata(langfuse.Metadata{\n\t\t\t\t\"engine\":      \"duckduckgo\",\n\t\t\t\t\"query\":       req.Query,\n\t\t\t\t\"max_results\": numResults,\n\t\t\t\t\"region\":      d.region(),\n\t\t\t\t\"error\":       err.Error(),\n\t\t\t}),\n\t\t)\n\n\t\tobs.LogErrorOrCancel(logger, err, \"failed to search in DuckDuckGo\")\n\t\t// DuckDuckGo already retries transient failures internally (see search);\n\t\t// by the time an error surfaces here, moving to the next engine is the\n\t\t// right call rather than burning another round-trip on the same one.\n\t\treturn \"\", Fatal(fmt.Errorf(\"duckduckgo search failed: %w\", err))\n\t}\n\n\treturn result, nil\n}\n\n// search performs a web search using DuckDuckGo\nfunc (d *duckduckgo) search(ctx context.Context, query string, maxResults int) (string, error) {\n\t// Build form data for POST request\n\tformData := d.buildFormData(query)\n\n\t// Create HTTP client with proper configuration\n\tclient, err := system.GetHTTPClient(d.cfg)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create http client: %w\", err)\n\t}\n\n\tclient.Timeout = duckduckgoTimeout\n","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/searchers/duckduckgo.go#L108-L144","documentation":"The DuckDuckGo searcher wraps any failure from its internal search() into a Fatal-classified error (`searchers.Fatal`). Per the searchers contract, Fatal means the orchestrator should NOT retry this engine and should move to the next engine in the fallbackStrategy chain. DuckDuckGo already retries transient failures internally, so anything surfacing here is considered terminal for this engine.","triggerScenarios":"Any error returned by d.search() after internal retries: HTTP client construction failure, request-build failure, transport errors after duckduckgoMaxRetries attempts, non-200 status after retries, body-read error, or HTML-parse error.","commonSituations":"DuckDuckGo rate-limiting or blocking the host (anomaly 403/202 responses); corporate egress proxy blocking duckduckgo.com; TLS interception breaking requests; DuckDuckGo changing HTML layout so parsing yields no results path-related errors; no internet/DNS failure in the container.","solutions":["Inspect the wrapped cause: if it's a network/status error, check egress connectivity and proxy settings (HTTP_PROXY/HTTPS_PROXY, cfg proxy config) for the container.","If it's a parse error, DuckDuckGo likely changed its HTML; update the selectors in parseHTMLStructured/parseHTMLRegex.","Verify other engines in the web_search fallback chain are configured so orchestration continues despite this Fatal error.","Reduce request volume or rotate egress IPs if you're seeing repeated 403s (rate-limit/bot detection)."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// before calling web_search, check the engine is reachable\nresp, err := http.Head(\"https://duckduckgo.com\")\nif err != nil || resp.StatusCode >= 500 {\n    // expect the duckduckgo searcher to fail; ensure other engines configured\n}","typeGuard":"var fatal searchers.FatalError\nif errors.As(err, &fatal) {\n    // do not retry this engine; orchestrator moves to next engine\n}","tryCatchPattern":"result, err := webSearch.Handle(ctx, req)\nif err != nil {\n    if searchers.IsFatal(err) {\n        log.Warn(\"duckduckgo failed terminally; falling back configured engines\")\n    }\n    return err // orchestrator already applied fallback chain\n}","preventionTips":["Always configure at least one alternate engine in the web_search fallback chain","Monitor engine error rates per engine to detect DuckDuckGo blocks early","Keep request volume within DuckDuckGo's tolerance; add jitter between queries","Verify container egress (DNS, proxy) during deployment health checks"],"tags":["network","search-engine","duckduckgo","rate-limit"],"backgroundTag":"search-engine-request-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}