{"record":{"id":"107830896446ab7d","repo":"chenhg5/cc-connect","slug":"read-body-from-s-w-107830","errorCode":null,"errorMessage":"read body from %s: %w","messagePattern":"read body from (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/skill_presets.go","lineNumber":133,"sourceCode":"\treturn c.data, nil\n}\n\nfunc fetchSkillPresetsFromURL(url string, timeout time.Duration) (*SkillPresetsResponse, error) {\n\tslog.Debug(\"fetching skill presets\", \"url\", url)\n\tclient := &http.Client{Timeout: timeout}\n\tresp, err := client.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"HTTP GET %s: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"HTTP GET %s: status %d\", url, resp.StatusCode)\n\t}\n\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read body from %s: %w\", url, err)\n\t}\n\n\tvar result SkillPresetsResponse\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse JSON from %s: %w\", url, err)\n\t}\n\treturn &result, nil\n}\n","sourceCodeStart":115,"sourceCodeEnd":142,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/skill_presets.go#L115-L142","documentation":"fetchSkillPresetsFromURL wraps io.ReadAll failures of the response body with \"read body from %s: %w\". The body is read through io.LimitReader(resp.Body, 1<<20) (1 MiB cap), so this fires when the connection breaks mid-read or the reader returns a non-EOF error.","triggerScenarios":"Connection reset or timeout while streaming the presets body; server closing the connection early (truncated response); TLS/proxy errors mid-transfer during fetch.","commonSituations":"Flaky Wi-Fi/mobile links; aggressive proxies killing long responses; very large or stalled responses from a misbehaving mirror.","solutions":["Retry the fetch — this is usually transient; other configured sources may succeed","Increase client.Timeout if slow-but-valid sources are being cut off mid-body, though the 1 MiB read cap stays","Check proxy/LB logs for early connection termination","Prefer a closer/faster mirror for the presets source"],"exampleFix":"// before\nresp, err := client.Get(url) // default timeout too short for slow mirror\n// after\nclient := &http.Client{Timeout: 60 * time.Second}\nresp, err := client.Get(url)","handlingStrategy":"retry","validationCode":"resp, err := http.Get(sourceURL)\nif err == nil {\n    n, err := io.Copy(io.Discard, io.LimitReader(resp.Body, 1<<20))\n    if err != nil { return fmt.Errorf(\"body unreadable from %s: %w\", sourceURL, err) }\n    if n == 0 { return fmt.Errorf(\"empty body from %s\", sourceURL) }\n}","typeGuard":null,"tryCatchPattern":"var presets *SkillPresetsResponse\nvar lastErr error\nfor attempt := 0; attempt < 3; attempt++ {\n    presets, lastErr = fetchSkillPresetsFromURL(url, timeout)\n    if lastErr == nil { break }\n    if strings.HasPrefix(lastErr.Error(), \"read body from\") {\n        time.Sleep(time.Duration(attempt+1) * time.Second)\n    }\n}\nif lastErr != nil { slog.Error(\"failed reading presets body\", \"url\", url, \"err\", lastErr) }","preventionTips":["Retry mid-body read failures — they are almost always transient network drops","Check proxies/LBs for idle-timeout settings that kill slow responses","Prefer nearby/fast mirrors for large preset files"],"tags":["network","http","io"],"backgroundTag":"network-request-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}