{"record":{"id":"8399a789e469bc22","repo":"charmbracelet/glow","slug":"unable-to-read-http-response-body-w","errorCode":null,"errorMessage":"unable to read http response body: %w","messagePattern":"unable to read http response body: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"github.go","lineNumber":35,"sourceCode":"\t\treturn nil, fmt.Errorf(\"invalid url: %s\", u.String())\n\t}\n\n\ttype readme struct {\n\t\tDownloadURL string `json:\"download_url\"`\n\t}\n\n\tapiURL := fmt.Sprintf(\"https://api.%s/repos/%s/%s/readme\", u.Hostname(), owner, repo)\n\n\t//nolint:bodyclose\n\t// it is closed on the caller\n\tres, err := http.Get(apiURL) //nolint: gosec,noctx\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to get url: %w\", err)\n\t}\n\n\tbody, err := io.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to read http response body: %w\", err)\n\t}\n\n\tvar result readme\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to parse json: %w\", err)\n\t}\n\n\tif res.StatusCode == http.StatusOK {\n\t\t//nolint:bodyclose\n\t\t// it is closed on the caller\n\t\tresp, err := http.Get(result.DownloadURL) //nolint: noctx\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to get url: %w\", err)\n\t\t}\n\n\t\tif resp.StatusCode == http.StatusOK {\n\t\t\treturn &source{resp.Body, result.DownloadURL}, nil\n\t\t}","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/charmbracelet/glow/blob/e3970c813d93da1ea84edfca90c289d9afb82242/github.go#L17-L53","documentation":"After the API responds, glow reads the whole body with io.ReadAll(res.Body); this error wraps a failure or interruption during that read. The connection was established and a response started, but the body transfer broke partway. Subsequent code (JSON parse, status check) never runs.","triggerScenarios":"Connection reset by peer or proxy mid-body; response truncated by a flaky NAT/VPN; keep-alive race where the server closes the connection during the read; captive portals that accept the handshake then cut the stream; timeouts enforced by an intermediary.","commonSituations":"Unstable Wi-Fi/VPN links; aggressive corporate proxies with short body-read timeouts; cloud NAT dropping long-lived sockets; intermittent ISP interception of GitHub traffic.","solutions":["Retry — transient mid-body resets usually clear on a second attempt","If persistent, capture where it dies: curl --raw -o /dev/null -w '%{size_download}' https://api.github.com/...","Bypass the suspect intermediary (different network, disable VPN, direct DNS) to identify the cutter","Fall back to the raw file URL or a local copy so the API body is not needed"],"exampleFix":"# transient: just retry\nglow https://github.com/owner/repo || glow https://github.com/owner/repo\n\n# if persistent, bypass the API body\nglow https://raw.githubusercontent.com/owner/repo/main/README.md","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"body, err := io.ReadAll(res.Body)\nif err != nil {\n\tvar ne net.Error\n\tif errors.As(err, &ne) && ne.Timeout() || errors.Is(err, syscall.ECONNRESET) {\n\t\t// mid-body transport failure: safe to retry the whole request idempotently\n\t\tfor i := 0; i < 3; i++ {\n\t\t\tres2, err2 := http.Get(apiURL)\n\t\t\tif err2 == nil {\n\t\t\t\tbody, err = io.ReadAll(res2.Body)\n\t\t\t\t_ = res2.Body.Close()\n\t\t\t\tif err == nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\ttime.Sleep(time.Duration(i+1) * 250 * time.Millisecond)\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to read http response body: %w\", err)\n\t}\n}","preventionTips":["Treat mid-body read failures as transient: retry the full GET rather than parsing partial bytes","Avoid networks/VPNs known to cut long-lived response bodies, or fetch the raw README instead","Set an explicit client timeout so hangs surface as errors you already handle"],"tags":["network","http","connection-reset","io","transient"],"backgroundTag":null,"analyzedSha":"e3970c813d93da1ea84edfca90c289d9afb82242","analyzedAt":"2026-08-15T22:50:54.304Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}