gastownhall/beads · error
read response: %w
Error message
read response: %w
What it means
Reading the Notion response body failed via io.ReadAll over an io.LimitReader capped at maxResponseBytes. This is uncommon and usually indicates the connection dropped mid-response, decompression failure, or a custom http.Client Transport returning a broken body reader.
Source
Thrown at internal/notion/client.go:288
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.Token)
req.Header.Set("Notion-Version", c.NotionVersion)
req.Header.Set("Accept", "application/json")
if requestBody != nil {
req.Header.Set("Content-Type", "application/json")
}
resp, err := httpClient.Do(req) //nolint:gosec // G704: URL is constructed from configured Notion API base, not user input
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes))
if err != nil {
return nil, fmt.Errorf("read response: %w", err)
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
return body, nil
}
var apiErr struct {
Code string `json:"code"`
Message string `json:"message"`
}
if err := json.Unmarshal(body, &apiErr); err == nil && apiErr.Message != "" {
return nil, fmt.Errorf("Notion API error %s (%d): %s", apiErr.Code, resp.StatusCode, apiErr.Message)
}
return nil, fmt.Errorf("Notion API error (%d): %s", resp.StatusCode, strings.TrimSpace(string(body)))
}
View on GitHub (pinned to 71377f2769)
Solutions
- Retry the request; this is usually transient (connection reset).
- Check for intermediaries (proxy, VPN, MITM) corrupting the response and bypass them.
- Inspect the wrapped error: unexpected EOF points at truncation; gzip errors point at encoding issues.
- If using a custom http.Client/Transport, test with the default transport to isolate the cause.
Example fix
// before
resp, err := doWithRetries(0)
body, err := readAll(resp) // fails, no retry
// after
var body []byte
for attempt := 0; attempt < 3; attempt++ {
body, err = doAndReadAll()
if err == nil {
break
}
time.Sleep(time.Duration(attempt+1) * time.Second)
} Defensive patterns
Strategy: retry
Try / catch
if err != nil && strings.Contains(err.Error(), "read response") {
// transient; retry the request with backoff
} Prevention
- Retry idempotent GETs on read failures.
- Avoid custom Transports unless necessary; test with the default client when debugging.
- Watch for proxies/VPN corrupting responses in restricted networks.
When it happens
Trigger: Connection reset while streaming the response body; gzip/deflate decode error when the transport is set to transparently decompress and the server/intermediary sends corrupt data; a custom Transport whose body reader returns a non-EOF error; the read error also fires if the response exceeds available resources in constrained environments.
Common situations: Unstable network/mobile hotspot dropping long responses; misbehaving corporate proxy truncating and corrupting responses; debugging proxies (custom Transport) with faulty RoundTrippers.
Related errors
- failed to read response (attempt %d/%d): %w
- failed to read response (attempt %d/%d): %w
- create request: %w
- failed to list projects: %w
- failed to read backup state: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/bffb51b4ec0be217.
Report an issue: GitHub.