{"record":{"id":"322af64bac9ee08f","repo":"Tencent/WeKnora","slug":"read-body-w-322af6","errorCode":null,"errorMessage":"read body: %w","messagePattern":"read body: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/utils/httputil.go","lineNumber":35,"sourceCode":"// raw bytes. It reuses a package-level http.Client with a 60-second timeout.\nfunc DownloadBytes(url string) ([]byte, error) {\n\tif !strings.HasPrefix(url, \"http://\") && !strings.HasPrefix(url, \"https://\") {\n\t\treturn nil, fmt.Errorf(\"unsupported URL scheme: %s\", url)\n\t}\n\tif err := ValidateURLForSSRF(url); err != nil {\n\t\treturn nil, fmt.Errorf(\"URL rejected by SSRF policy: %w\", err)\n\t}\n\tresp, err := defaultHTTPClient.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"HTTP GET: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"HTTP %d for %s\", resp.StatusCode, url)\n\t}\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read body: %w\", err)\n\t}\n\treturn data, nil\n}\n","sourceCodeStart":17,"sourceCodeEnd":39,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/httputil.go#L17-L39","documentation":"DownloadBytes reads the entire response body with io.ReadAll after confirming status 200; an I/O failure mid-read (connection reset, premature close, truncated chunked encoding) is wrapped as \"read body: <cause>\".","triggerScenarios":"Calling DownloadBytes when the connection drops while streaming the body: server closes prematurely, network interruption, proxy/CDN truncation, or chunked encoding errors.","commonSituations":"Flaky mobile/satellite uplinks on the server side, large downloads over unstable connections, aggressive LB idle timeouts killing long transfers, or misbehaving CDNs/proxies cutting responses short.","solutions":["Retry the download with exponential backoff — transient resets often succeed on retry","Use a resumable/range-request download for large files","Verify intermediate proxies/CDNs aren't truncating the response","Check server-side stability of the endpoint; for huge payloads consider a different transfer mechanism (fetch in chunks)"],"exampleFix":"// before\ndata, err := DownloadBytes(url) // read body: unexpected EOF\n// after\nvar data []byte\nerr := retryWithBackoff(3, func() error {\n    var e error\n    data, e = DownloadBytes(url)\n    return e\n})","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var data []byte\nerr := retryWithBackoff(3, time.Second, func() error {\n    var e error\n    data, e = DownloadBytes(url)\n    if e != nil && strings.Contains(e.Error(), \"read body:\") {\n        return e // transient truncation — retry\n    }\n    return e\n})","preventionTips":["Retry truncated reads with backoff — mid-body resets are usually transient","Use chunked/range resumable downloads for large payloads","Check intermediate proxies/CDNs/LBs for idle-timeout truncation","Avoid downloading very large bodies on unstable network paths"],"tags":["network","http","io","go"],"backgroundTag":"connection-reset","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}