{"record":{"id":"610283b1f000417a","repo":"siyuan-note/siyuan","slug":"failed-to-read-response-body-w","errorCode":null,"errorMessage":"failed to read response body: %w","messagePattern":"failed to read response body: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_client.go","lineNumber":141,"sourceCode":"\t\t\t\t}\n\t\t\t\tr.SetHeader(model.XAuthTokenKey, p.token)\n\n\t\t\t\tif bodyString != nil {\n\t\t\t\t\tr.SetBody(*bodyString)\n\t\t\t\t} else if bodyBytes != nil {\n\t\t\t\t\tr.SetBody(*bodyBytes)\n\t\t\t\t}\n\n\t\t\t\tresp, sendErr := r.Send(method, targetURL)\n\t\t\t\tif sendErr != nil {\n\t\t\t\t\terr = sendErr\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tdefer resp.Body.Close()\n\t\t\t\tbody, readErr := io.ReadAll(resp.Body)\n\t\t\t\tif readErr != nil {\n\t\t\t\t\terr = fmt.Errorf(\"failed to read response body: %w\", readErr)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tresponseHeader := map[string]string{}\n\t\t\t\tfor k, vs := range resp.Header {\n\t\t\t\t\tresponseHeader[k] = strings.Join(vs, \", \")\n\t\t\t\t}\n\n\t\t\t\trunErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {\n\t\t\t\t\tresponse := rt.NewObject()\n\t\t\t\t\tlo.Must0(response.Set(\"url\", rt.ToValue(path)))\n\t\t\t\t\tlo.Must0(response.Set(\"ok\", rt.ToValue(resp.StatusCode >= 200 && resp.StatusCode < 300)))\n\t\t\t\t\tlo.Must0(response.Set(\"status\", rt.ToValue(resp.StatusCode)))\n\t\t\t\t\tlo.Must0(response.Set(\"statusText\", rt.ToValue(resp.Status)))\n\t\t\t\t\tlo.Must0(response.Set(\"headers\", rt.ToValue(responseHeader)))\n\t\t\t\t\tlo.Must0(ObjectSetDataMethods(p, rt, response, body))\n\t\t\t\t\tresult = response\n\t\t\t\t\treturn","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/api_client.go#L123-L159","documentation":"The plugin API client received an HTTP response but io.ReadAll(resp.Body) failed while draining the response body. The client wraps the underlying read error (%w) so the transport-level cause (connection reset, premature EOF, timeout mid-body) is preserved. It means the request was sent and headers arrived, but the body could not be fully read.","triggerScenarios":"Calling siyuan.client.request/fetch from a plugin when the kernel closes the connection mid-transfer, the server times out while streaming the body, a proxy truncates the response, or the network drops between headers and body.","commonSituations":"Large kernel API responses (e.g. export or SQL query results) over flaky networks; reverse proxies with short idle timeouts; container networks dropping keepalive connections; mobile/unstable connections.","solutions":["Read the wrapped readErr in the message to identify the transport cause (unexpected EOF, connection reset, context deadline).","Retry the request; transient body-read failures usually succeed on retry.","Check proxy/load-balancer timeout settings between the plugin host and the kernel.","Reduce response size (narrow the API query) or increase network timeouts.","Verify kernel logs for panics or connection resets at the same timestamp."],"exampleFix":"// before\nconst data = await client.request('/api/query/sql', { stmt: 'SELECT * FROM blocks' });\n// after\ntry {\n  const data = await client.request('/api/query/sql', { stmt: 'SELECT * FROM blocks' });\n} catch (e) {\n  if (String(e).includes('failed to read response body')) {\n    // retry once or fall back to a paginated query\n    const data = await client.request('/api/query/sql', { stmt: 'SELECT * FROM blocks LIMIT 1000' });\n  }\n}","handlingStrategy":"retry","validationCode":"// no pre-call check possible; validate response handling instead\nif (!navigator.onLine) { await waitForNetwork(); }","typeGuard":null,"tryCatchPattern":"try {\n  const data = await client.request(path, payload);\n} catch (e) {\n  if (String(e).includes('failed to read response body')) {\n    data = await withRetry(() => client.request(path, payload), 2);\n  } else { throw e; }\n}","preventionTips":["Implement idempotent retry with backoff for kernel API calls","Keep payloads/responses modest in size or paginate large queries","Check proxy and load-balancer idle timeouts in deployment configs"],"tags":["network","http","plugin-api"],"backgroundTag":"http-request-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}