{"record":{"id":"3b94c6bdf23f0bdc","repo":"siyuan-note/siyuan","slug":"read-body-failed-s","errorCode":null,"errorMessage":"read body failed: %s","messagePattern":"read body failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/httprequest.go","lineNumber":109,"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":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/httprequest.go#L91-L127","documentation":"Returned by HTTPRequest when io.ReadAll on the LimitReader-bounded body fails. At this point headers (status, Content-Type, Content-Length) were already read successfully; the failure is mid-stream while reading the response body. The underlying read error is appended for diagnostics.","triggerScenarios":"After receiving response headers, the connection drops or stalls while the body is still being read; the server closes the connection early; the LimitReader hits a transient I/O error. Note: because LimitReader is used, EOF after the cap is not an error — this fires only on an actual read failure.","commonSituations":"An unstable network link, a server that times out mid-response, a proxy that closes idle connections, or a server streaming a body larger than the cap and the connection being reset before truncation completes.","solutions":["Retry the request once — mid-stream read failures are often transient.","If recurring, reduce the requested payload (paginate) so the body completes before any connection idle timeout.","Inspect the appended I/O error text to distinguish a reset ('connection reset') from a timeout ('i/o timeout')."],"exampleFix":"// before\n_, _, _, err := util.HTTPRequest(\"GET\", rawURL, nil, \"\")\n\n// after\nvar err error\nfor attempt := 0; attempt < 2; attempt++ {\n    _, _, _, err = util.HTTPRequest(\"GET\", rawURL, nil, \"\")\n    if err == nil || !strings.Contains(err.Error(), \"read body failed\") {\n        break\n    }\n    time.Sleep(500 * time.Millisecond)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var err error\nfor attempt := 0; attempt < 2; attempt++ {\n    _, _, _, err = util.HTTPRequest(method, rawURL, headers, body)\n    if err == nil || !strings.Contains(err.Error(), \"read body failed\") { break }\n    time.Sleep(500 * time.Millisecond)\n}","preventionTips":["Retry once on mid-stream read failures; they are usually transient.","Narrow large payloads so the body completes before any idle timeout."],"tags":["network","http","transport","io","http-request"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}