{"record":{"id":"a652391171e3ab30","repo":"siyuan-note/siyuan","slug":"web-search-failed-s","errorCode":null,"errorMessage":"web search failed: %s","messagePattern":"web search failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/websearch.go","lineNumber":83,"sourceCode":"\n\treqBody := mcpRequest{\n\t\tJSONRPC: \"2.0\",\n\t\tID:      1,\n\t\tMethod:  \"tools/call\",\n\t\tParams: mcpParams{\n\t\t\tName: \"web_search_exa\",\n\t\t\tArguments: map[string]any{\n\t\t\t\t\"query\":      query,\n\t\t\t\t\"type\":       \"auto\",\n\t\t\t\t\"numResults\": 8,\n\t\t\t\t\"livecrawl\":  \"fallback\",\n\t\t\t},\n\t\t},\n\t}\n\n\tresp, err := httpclient.NewBrowserRequest().SetHeader(\"Accept\", \"application/json, text/event-stream\").SetBody(reqBody).Post(exaURL)\n\tif err != nil {\n\t\treturn \"\", errors.New(\"web search failed: \" + err.Error())\n\t}\n\tdefer resp.Body.Close()\n\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", errors.New(\"web search read response failed: \" + err.Error())\n\t}\n\tbody := string(bodyBytes)\n\n\tpreview := body\n\tif len(preview) > 500 {\n\t\tpreview = body[:500]\n\t}\n\tlogging.LogInfof(\"websearch response: status=%d, len=%d, preview=%s\", resp.StatusCode, len(body), preview)\n\n\ttext := parseMcpResponse(body)\n\tif text == \"\" {\n\t\treturn \"No search results found. Please try a different query.\", nil","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/websearch.go#L65-L101","documentation":"WebSearch in kernel/util/websearch.go performs an Exa web-search request via httpclient. When the HTTP POST itself fails (transport-level error, not an HTTP error status), it wraps the underlying error into \"web search failed: <err>\" and returns it to the caller webSearchHandler.","triggerScenarios":"Calling WebSearch when the network is down, DNS for the Exa endpoint fails, the request times out at the transport layer, TLS handshake fails, or a proxy misconfiguration blocks the outgoing POST.","commonSituations":"Offline or restricted environments, corporate proxies/firewalls blocking api.exa.ai, missing system CA certificates, IPv6/DNS issues in containers.","solutions":["Check basic network connectivity to the Exa endpoint from the machine running the kernel","Inspect the wrapped cause after 'web search failed:' for DNS/timeout/TLS specifics","Verify proxy environment variables (HTTP_PROXY/HTTPS_PROXY) are correct or unset as appropriate","Ensure system CA certificates are installed and current","Retry after connectivity is restored; the failure is transient in most network cases"],"exampleFix":"// before\nif err != nil {\n\treturn \"\", errors.New(\"web search failed: \" + err.Error())\n}\n// after: keep context and unwrap-able chain\nif err != nil {\n\treturn \"\", fmt.Errorf(\"web search failed: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: probe connectivity before calling WebSearch\nconn, err := net.DialTimeout(\"tcp\", \"api.exa.ai:443\", 3*time.Second)\nif err != nil { return fmt.Errorf(\"web search unavailable: %w\", err) }\nconn.Close()","typeGuard":null,"tryCatchPattern":"results, err := util.WebSearch(...)\nif err != nil && strings.HasPrefix(err.Error(), \"web search failed:\") {\n\t// inspect wrapped cause; retry with backoff or surface offline state\n}","preventionTips":["Ensure outbound HTTPS to the search API is allowed by proxy/firewall","Keep system CA certificates current","Handle offline mode gracefully in UI before invoking search"],"tags":["network","http","websearch"],"backgroundTag":"http-request-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}