goreleaser/goreleaser · warning

could not read from body: %w

Error message

could not read from body: %w

What it means

This error wraps io.ReadAll failing while draining the response body of a successful (2xx) POST /v2/shares response. Reading a response body only fails on I/O problems mid-stream: the connection was reset or timed out before the full body arrived, or the body was already closed/consumed. It is rare and happens after LinkedIn already accepted the share, so the post may have succeeded even though the activity URL was lost.

Source

Thrown at internal/pipe/linkedin/client.go:227

	req.Header.Set("Content-Type", "application/json")

	resp, err := c.client.Do(req)
	if err != nil {
		return "", fmt.Errorf("could not POST /v2/shares: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode >= http.StatusBadRequest {
		body, _ := io.ReadAll(resp.Body)
		return "", retryx.HTTP(gerrors.Wrap(
			fmt.Errorf("POST /v2/shares returned %d %s", resp.StatusCode, http.StatusText(resp.StatusCode)),
			gerrors.WithOutput(string(body)),
		), resp)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("could not read from body: %w", err)
	}

	var result shareResponse
	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("could not unmarshal: %w", err)
	}

	// Activity URN
	// URN of the activity associated with this share. Activities act as a wrapper around
	// shares and articles to represent content in the LinkedIn feed. Read only.
	if result.Activity == "" {
		return "", errors.New("could not find 'activity' in result")
	}
	return fmt.Sprintf("https://www.linkedin.com/feed/update/%s", result.Activity), nil
}

View on GitHub (pinned to f5edd73956)

Solutions

  1. Re-run the pipeline — the share may have already been posted; check your LinkedIn feed before reposting to avoid duplicates.
  2. Read the wrapped error: 'unexpected EOF'/'connection reset' indicates a network drop — improve network stability or retry with backoff.
  3. Check for proxies/middleboxes (corporate proxies, VPN) that truncate long-lived responses; bypass them for api.linkedin.com.
  4. If 'http: read on closed response body' appears, it's a bug in a fork/patched transport — report upstream.
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify a full request/response roundtrip works
resp, err := http.Get("https://api.linkedin.com/v2/userinfo")
if err == nil {
    _, err = io.ReadAll(resp.Body) // proves bodies can be fully drained
    resp.Body.Close()
}
if err != nil {
    return fmt.Errorf("network cannot reliably read linkedin responses: %w", err)
}

Try / catch

url, err := client.Share(ctx, msg)
if err != nil && strings.Contains(err.Error(), "could not read from body") {
    // share may have succeeded; check before retrying to avoid duplicates
    log.Warnf("share response body read failed, post may exist: %v", err)
    return nil // or verify via feed lookup instead of reposting
}

Prevention

When it happens

Trigger: Network connection reset or context deadline expiring while reading the 2xx response body; server closing the connection prematurely (chunked encoding truncated); body previously closed by a wrapped transport.

Common situations: Flaky Wi-Fi/VPN dropping the connection right after LinkedIn returns 200; CI runner with aggressive idle connection timeouts; oauth2/http transport closing responses unexpectedly; extremely slow proxy truncating the response.

Related errors


AI-assisted analysis of goreleaser/goreleaser@f5edd73956 (2026-09-05). Data as JSON: /api/errors/effde0e87906c796. Report an issue: GitHub.