siyuan-note/siyuan · error
web search read response failed: %s
Error message
web search read response failed: %s
What it means
Returned at websearch.go:89 when io.ReadAll(resp.Body) fails after the POST to Exa connected and headers came back. Unlike WebFetch, this reader has NO size limit applied — the entire response body is read into memory. The %s is the stream read error.
Source
Thrown at kernel/util/websearch.go:89
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
}
return truncateRunes(text, maxWebSearchChars), nil
}
func parseMcpResponse(body string) string {View on GitHub (pinned to 251596fc0d)
Solutions
- Retry the search — stream drops are often transient.
- Stabilise the network path (disable flaky VPN, switch off aggressive proxy timeouts).
- Be aware there is no body-size cap; on pathological responses the process can grow large before failing.
- If repeatable, capture resp.StatusCode (logged at websearch.go:97) to distinguish a server-side truncation.
Defensive patterns
Strategy: retry
Type guard
func isWebSearchReadFailed(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "web search read response failed:")
} Try / catch
out, err := util.WebSearch(q, key)
if err != nil && isWebSearchReadFailed(err) {
// mid-stream drop, often transient
out, err = util.WebSearch(q, key)
} Prevention
- Retry once — body-stream drops during livecrawl are frequently transient.
- Be aware WebSearch reads the whole body with no size cap; monitor memory on pathological responses.
- Stabilise the network path (VPN/proxy timeouts) for long-running searches.
When it happens
Trigger: Connection reset mid-stream, read timeout while Exa's livecrawl is still producing output, server closing the SSE/streaming channel early, or memory pressure on an unusually large response.
Common situations: Slow/unstable network during a long livecrawl, intermediary dropping long-lived responses, Exa returning an unexpectedly large payload, client read deadline too tight.
Related errors
- read body failed: %s
- web search failed: %s
- read custom emoji response failed: %w
- read body failed: %s
- read body failed: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/13885c22782996ca.
Report an issue: GitHub.