{"record":{"id":"3b94c6bdf23f0bdc","repo":"siyuan-note/siyuan","slug":"read-body-failed-s","errorCode":null,"errorMessage":"read body failed: %s","messagePattern":"read body failed: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/httprequest.go","lineNumber":356,"sourceCode":"\t\treturn 0, \"\", \"\", errors.New(\"nil response\")\n\t}\n\tdefer resp.Body.Close()\n\n\tstatusCode = resp.StatusCode\n\tcontentType = resp.Header.Get(\"Content-Type\")\n\n\tmaxReadBytes := int64(maxHTTPRequestBytes)\n\tif !isTextContentType(contentType) {\n\t\tmaxReadBytes = maxHTTPRequestFileBytes\n\t}\n\t// ContentLength 为 -1（chunked）时跳过大小预检，交由 LimitReader 兜底截断。\n\tif resp.ContentLength > maxReadBytes {\n\t\treturn statusCode, contentType, \"\", errors.New(\"response too large\")\n\t}\n\n\trespBody, rerr := io.ReadAll(io.LimitReader(resp.Body, maxReadBytes))\n\tif rerr != nil {\n\t\treturn statusCode, contentType, \"\", errors.New(\"read body failed: \" + rerr.Error())\n\t}\n\n\t// 二进制响应落盘，返回文件路径，供智能体按需进一步处理。\n\tif !isTextContentType(contentType) {\n\t\timportDir := filepath.Join(TempDir, \"import\")\n\t\tif merr := os.MkdirAll(importDir, 0755); merr != nil {\n\t\t\treturn statusCode, contentType, \"\", errors.New(\"create import dir failed: \" + merr.Error())\n\t\t}\n\t\tfilename := extractFilename(rawURL, contentType)\n\t\tfilePath := filepath.Join(importDir, filename)\n\t\tif werr := os.WriteFile(filePath, respBody, 0644); werr != nil {\n\t\t\treturn statusCode, contentType, \"\", errors.New(\"write file failed: \" + werr.Error())\n\t\t}\n\t\treturn statusCode, contentType, fmt.Sprintf(\"Saved to: %s (%d bytes)\", filePath, len(respBody)), nil\n\t}\n\n\treturn statusCode, contentType, truncateRunes(string(respBody), maxHTTPRequestChars), nil\n}","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/util/httprequest.go#L338-L374","documentation":"Reading the response body failed mid-stream: io.ReadAll over io.LimitReader returned an error, and the suffix carries it. Headers and status were already received, so this is a connection that broke during the body - reset by peer, TLS error, or the 30-second client timeout expiring while streaming. The status code and content type are still returned alongside the error.","triggerScenarios":"Server closes the connection early (bad Content-Length, crashing handler); flaky network resets the stream; slow transfer of a near-cap body that cannot finish within the client's 30s total budget.","commonSituations":"Mobile or unstable links; overloaded origins that drop long responses; proxies cutting long transfers; responses whose declared length disagrees with actual bytes.","solutions":["Retry the request - mid-body failures are usually transient; use short backoff","Shrink the response (pagination, filters, Range) so the transfer finishes well inside 30 seconds","Reproduce with curl --limit-rate or plain curl to see whether the server itself truncates the stream"],"exampleFix":"// before: one attempt\ncode, ct, text, err := util.HTTPRequest(\"GET\", u, nil, \"\")\n\n// after: retry on mid-body failure\nfor attempt := 0; attempt < 3; attempt++ {\n    code, ct, text, err = util.HTTPRequest(\"GET\", u, nil, \"\")\n    if err == nil || !strings.Contains(err.Error(), \"read body failed\") {\n        break\n    }\n    time.Sleep(time.Duration(attempt+1) * time.Second)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    code, ct, text, err = util.HTTPRequest(\"GET\", u, nil, \"\")\n    if err == nil || !strings.Contains(err.Error(), \"read body failed\") {\n        break\n    }\n    time.Sleep(time.Duration(attempt+1) * time.Second)\n}","preventionTips":["Shrink responses (pagination, filters, Range) so transfers finish well inside the 30-second total budget","Prefer stable wired networks for large fetches","Treat repeated mid-body failures on one endpoint as a server-side truncation problem; verify with curl"],"tags":["network","http","timeout","agent-tools"],"backgroundTag":"response-body-read-failed","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}