{"record":{"id":"33035a5df03c4c0d","repo":"Tencent/WeKnora","slug":"read-body-failed-w","errorCode":null,"errorMessage":"read body failed: %w","messagePattern":"read body failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/datasource/connector/rss/client.go","lineNumber":89,"sourceCode":"\t}\n\tif req.Header.Get(\"Accept\") == \"\" {\n\t\treq.Header.Set(\"Accept\",\n\t\t\t\"application/rss+xml, application/atom+xml, application/xml, text/xml, application/json, text/html;q=0.9, */*;q=0.8\")\n\t}\n\n\tresp, err := c.httpClient.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fetch failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn nil, fmt.Errorf(\"HTTP %d %s\", resp.StatusCode, resp.Status)\n\t}\n\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxSize))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read body failed: %w\", err)\n\t}\n\treturn body, nil\n}\n\n// fetchFeed retrieves the raw bytes of a feed document.\nfunc (c *client) fetchFeed(ctx context.Context, feedURL string) ([]byte, error) {\n\treturn c.fetch(ctx, feedURL, maxFeedSize, true)\n}\n\n// extractArticle fetches an article page and returns the readability-cleaned\n// main content as HTML, plus the extracted title (may be empty). Returns an\n// error if the page can't be fetched or no readable content is found, so the\n// caller can fall back to feed-provided content.\nfunc (c *client) extractArticle(ctx context.Context, articleURL string) (contentHTML, title string, err error) {\n\tbody, err := c.fetch(ctx, articleURL, maxArticleSize, false)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/datasource/connector/rss/client.go#L71-L107","documentation":"Returned when reading the HTTP response body fails after a 2xx status. The body is read through io.LimitReader capped at maxSize (10 MB for feeds, 5 MB for articles), so this error comes from a broken/truncated connection, an unexpected EOF, a decompression failure (e.g. malformed gzip), or the request context timing out mid-read.","triggerScenarios":"The server closes the connection before sending the full body; a proxy or CDN truncates the response; the response uses gzip/deflate/brotli with corrupt bytes; the 20s context deadline expires while streaming a large body.","commonSituations":"Flaky mobile/behind-NAT feed hosts dropping connections; misconfigured CDNs sending a Content-Encoding the client cannot decompress; very large feeds on slow links hitting the 20-second timeout; load balancers with short idle timeouts.","solutions":["Retry the fetch — truncation is usually transient; wrap the call in a retry with backoff.","If timeouts recur, reduce the amount fetched (trim the feed) or increase requestTimeout; note the maxSize LimitReader caps memory but not time.","Bypass or fix a misconfigured proxy/CDN that is corrupting Content-Encoding; test with curl --compressed.","Check server-side logs on the feed host for crashes or connection resets."],"exampleFix":"// before\ndata, err := cli.fetchFeed(ctx, feedURL)\n// after\nvar data []byte\nvar err error\nfor i := 0; i < 3; i++ {\n    data, err = cli.fetchFeed(ctx, feedURL)\n    if err == nil || !isTransientReadError(err) {\n        break\n    }\n    time.Sleep(time.Duration(1<<i) * time.Second)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"data, err := cli.fetchFeed(ctx, feedURL)\nif err != nil {\n    if isTruncated(err) { // io.ErrUnexpectedEOF / context deadline in message\n        ctx2, cancel := context.WithTimeout(ctx, 60*time.Second)\n        defer cancel()\n        data, err = cli.fetchFeed(ctx2, feedURL)\n    }\n    if err != nil {\n        return fmt.Errorf(\"feed %s: %w\", feedURL, err)\n    }\n}","preventionTips":["Retry truncated reads — they are almost always transient.","Raise requestTimeout for known-large or slow feeds.","Check proxy/CDN Content-Encoding configuration if errors repeat for one host.","Cap feed sizes server-side so slow streaming is bounded."],"tags":["network","http","io","timeout"],"backgroundTag":"body-read-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}