charmbracelet/glow · error
unable to read http response body: %w
Error message
unable to read http response body: %w
What it means
glow fetches GitLab READMEs via the v4 REST API: it builds https://<host>/api/v4/projects/<path>, calls http.Get, then streams the body with io.ReadAll. This error means the HTTP request itself succeeded but reading the response body failed; the underlying I/O error is wrapped with %w. It almost always indicates a connection that dropped or was cut after the response headers were received.
Source
Thrown at gitlab.go:37
projectPath := url.QueryEscape(owner + "/" + repo)
type readme struct {
ReadmeURL string `json:"readme_url"`
}
apiURL := fmt.Sprintf("https://%s/api/v4/projects/%s", u.Hostname(), projectPath)
//nolint:bodyclose
// it is closed on the caller
res, err := http.Get(apiURL) //nolint: gosec,noctx
if err != nil {
return nil, fmt.Errorf("unable to get url: %w", err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("unable to read http response body: %w", err)
}
var result readme
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("unable to parse json: %w", err)
}
readmeRawURL := strings.ReplaceAll(result.ReadmeURL, "blob", "raw")
if res.StatusCode == http.StatusOK {
//nolint:bodyclose
// it is closed on the caller
resp, err := http.Get(readmeRawURL) //nolint: gosec,noctx
if err != nil {
return nil, fmt.Errorf("unable to get url: %w", err)
}
if resp.StatusCode == http.StatusOK {View on GitHub (pinned to e3970c813d)
Solutions
- Retry the command - transient connection drops are the most common cause
- Reproduce outside glow: curl https://gitlab.com/api/v4/projects/<owner>%2F<repo> and watch for truncation
- For self-hosted GitLab, raise reverse-proxy read timeouts (e.g. nginx proxy_read_timeout)
- Test from a different network to rule out VPN/proxy interference
Defensive patterns
Strategy: retry
Validate before calling
func gitlabAPIReadable(host, projectPath string) error {
u := fmt.Sprintf("https://%s/api/v4/projects/%s", host, projectPath)
client := &http.Client{Timeout: 15 * time.Second}
res, err := client.Get(u) //nolint:noctx
if err != nil { return err }
defer res.Body.Close()
_, err = io.Copy(io.Discard, io.LimitReader(res.Body, 1<<20))
return err
} Type guard
func isTransientNetErr(err error) bool {
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) { return dnsErr.IsTemporary }
var opErr *net.OpError
return errors.As(err, &opErr)
} Try / catch
var body []byte
for attempt := 0; attempt < 3; attempt++ {
var err error
body, err = fetchGitLabAPI(u)
if err == nil { break }
if !isTransientNetErr(err) { return err }
time.Sleep(time.Duration(attempt+1) * 500 * time.Millisecond)
} Prevention
- Use an http.Client with an explicit Timeout instead of bare http.Get so stalled bodies fail fast
- Retry transient network errors with backoff before surfacing them to the user
- Watch for proxy interference when fetching from self-hosted GitLab
When it happens
Trigger: http.Get to the GitLab projects API returns headers, then the TCP connection resets or times out mid-body; a proxy or middlebox truncates the transfer; a TLS problem surfaces during body streaming; the server closes the connection early.
Common situations: Flaky Wi-Fi or VPN links, corporate proxies that cut long streams, self-hosted GitLab behind nginx/traefik with an aggressive proxy_read_timeout, CI runners with restricted egress.
Related errors
- can't find README in GitLab repository
- unable to read http response body: %w
- unable to get url: %w
- can't find README in GitHub repository
- unable to get url: %w
AI-assisted analysis of charmbracelet/glow@e3970c813d (2026-08-15).
Data as JSON: /api/errors/bab31f9cd85db678.
Report an issue: GitHub.