siyuan-note/siyuan · error

read body failed: %s

Error message

read body failed: %s

What it means

Returned at webfetch.go:75 when io.ReadAll(io.LimitReader(resp.Body, maxReadBytes)) fails. Headers were received fine, but the body stream broke partway through. The %s is the io error (e.g. connection reset, read deadline, unexpected EOF).

Source

Thrown at kernel/util/webfetch.go:75

	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		return "", fmt.Errorf("HTTP %d", resp.StatusCode)
	}

	contentType := resp.Header.Get("Content-Type")
	maxReadBytes := int64(maxWebFetchBytes)
	if !strings.HasPrefix(contentType, "text/html") && !strings.HasPrefix(contentType, "text/plain") {
		maxReadBytes = maxWebFetchFileBytes
	}
	if resp.ContentLength > maxReadBytes {
		return "", errors.New("response too large")
	}

	body, err := io.ReadAll(io.LimitReader(resp.Body, maxReadBytes))
	if err != nil {
		return "", errors.New("read body failed: " + err.Error())
	}

	if !strings.HasPrefix(contentType, "text/html") && !strings.HasPrefix(contentType, "text/plain") {
		importDir := filepath.Join(TempDir, "import")
		if merr := os.MkdirAll(importDir, 0755); merr != nil {
			return "", errors.New("create import dir failed: " + merr.Error())
		}
		filename := extractFilename(rawURL, contentType)
		filePath := filepath.Join(importDir, filename)
		if werr := os.WriteFile(filePath, body, 0644); werr != nil {
			return "", errors.New("write file failed: " + werr.Error())
		}
		return fmt.Sprintf("Saved to: %s (%d bytes)", filePath, len(body)), nil
	}

	htmlStr := string(body)

	isHTML := strings.HasPrefix(contentType, "text/html")

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Retry the fetch once — body-stream errors are frequently transient.
  2. If repeatable, test with `curl --limit-rate` and a longer timeout to characterise the drop.
  3. Check whether a proxy/VPN in the path is killing long responses.
  4. For very slow links, raise the httpclient read timeout if configurable in your build.
Defensive patterns

Strategy: retry

Type guard

func isReadBodyFailed(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "read body failed:")
}

Try / catch

out, err := util.WebFetch(raw, "markdown")
if err != nil && isReadBodyFailed(err) {
    // mid-stream drop: retry once
    out, err = util.WebFetch(raw, "markdown")
}

Prevention

When it happens

Trigger: Connection reset by peer mid-download, read timeout (client or server side), server closing the keep-alive socket early, TLS renegotiation failure, or the process hitting its read deadline on a slow link.

Common situations: Unstable mobile/tethered network, slow CDN that times out, server killing slow clients, intermediary (proxy/NAT) dropping idle connections.

Related errors


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