siyuan-note/siyuan · error

web search failed

Error message

web search failed: %s

What it means

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.

Solutions

  1. Check basic network connectivity to the Exa endpoint from the machine running the kernel
  2. Inspect the wrapped cause after 'web search failed:' for DNS/timeout/TLS specifics
  3. Verify proxy environment variables (HTTP_PROXY/HTTPS_PROXY) are correct or unset as appropriate
  4. Ensure system CA certificates are installed and current
  5. Retry after connectivity is restored; the failure is transient in most network cases

Example fix

// before
if err != nil {
	return "", errors.New("web search failed: " + err.Error())
}
// after: keep context and unwrap-able chain
if err != nil {
	return "", fmt.Errorf("web search failed: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: probe connectivity before calling WebSearch
conn, err := net.DialTimeout("tcp", "api.exa.ai:443", 3*time.Second)
if err != nil { return fmt.Errorf("web search unavailable: %w", err) }
conn.Close()

Try / catch

results, err := util.WebSearch(...)
if err != nil && strings.HasPrefix(err.Error(), "web search failed:") {
	// inspect wrapped cause; retry with backoff or surface offline state
}

Prevention

When it happens

Trigger: 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.

Common situations: Offline or restricted environments, corporate proxies/firewalls blocking api.exa.ai, missing system CA certificates, IPv6/DNS issues in containers.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/a652391171e3ab30. Report an issue: GitHub.

Appendix: 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 9f775e8a12)