siyuan-note/siyuan · error

web search failed: %s

Error message

web search failed: %s

What it means

Returned at websearch.go:83 when httpclient.NewBrowserRequest().Post(exaURL) fails at the transport layer before any response body is available. exaURL defaults to https://mcp.exa.ai/mcp (websearch.go:31), appended with ?exaApiKey=... when a key is supplied (websearch.go:62-64). An empty key still issues the request, just unauthenticated. The %s is the underlying transport error.

Source

Thrown at kernel/util/websearch.go:83

	reqBody := mcpRequest{
		JSONRPC: "2.0",
		ID:      1,
		Method:  "tools/call",
		Params: mcpParams{
			Name: "web_search_exa",
			Arguments: map[string]any{
				"query":      query,
				"type":       "auto",
				"numResults": 8,
				"livecrawl":  "fallback",
			},
		},
	}

	resp, err := httpclient.NewBrowserRequest().SetHeader("Accept", "application/json, text/event-stream").SetBody(reqBody).Post(exaURL)
	if err != nil {
		return "", errors.New("web search failed: " + err.Error())
	}
	defer resp.Body.Close()

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", errors.New("web search read response failed: " + err.Error())
	}
	body := string(bodyBytes)

	preview := body
	if len(preview) > 500 {
		preview = body[:500]
	}
	logging.LogInfof("websearch response: status=%d, len=%d, preview=%s", resp.StatusCode, len(body), preview)

	text := parseMcpResponse(body)
	if text == "" {
		return "No search results found. Please try a different query.", nil

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Confirm the host is reachable from the SiYuan host: `curl -I https://mcp.exa.ai/mcp`.
  2. Verify internet connectivity and DNS for mcp.exa.ai.
  3. Check/correct HTTP_PROXY / HTTPS_PROXY env vars.
  4. Retry once for transient network blips.
Defensive patterns

Strategy: retry

Validate before calling

// Confirm the Exa MCP host is reachable before issuing the search.
func exaReachable() error {
    if _, err := net.LookupHost("mcp.exa.ai"); err != nil {
        return fmt.Errorf("dns: %w", err)
    }
    return nil
}

Type guard

func isWebSearchFailed(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "web search failed:")
}

Try / catch

out, err := util.WebSearch(q, key)
if err != nil && isWebSearchFailed(err) {
    // transport-level: back off and retry once
    out, err = util.WebSearch(q, key)
}

Prevention

When it happens

Trigger: Calling util.WebSearch(query, key) with no network, mcp.exa.ai unresolvable, TLS handshake failure, proxy pointing at a dead upstream, or an egress firewall blocking the Exa host.

Common situations: Air-gapped/offline host, corporate firewall blocking mcp.exa.ai, broken HTTP_PROXY, captive portal intercepting TLS, IPv6 connectivity problems.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/a652391171e3ab30. Report an issue: GitHub.