chenhg5/cc-connect · error

weixin: %s: read body: %w

Error message

weixin: %s: read body: %w

What it means

post() fails while reading the response body with io.ReadAll (bounded by maxIlinkHTTPResponseBody = 64 MiB via io.LimitReader). This wraps I/O errors from the connection while draining the body, e.g. the server or an intermediary closed the connection mid-response.

Source

Thrown at platform/weixin/client.go:109

	}
	if c.routeTag != "" {
		req.Header.Set("SKRouteTag", c.routeTag)
	}

	client := c.httpClient
	if timeout > 0 {
		// Dedicated client so long-poll does not inherit short Timeout from default client.
		client = c.longPollClient(timeout)
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("weixin: %s: %w", label, err)
	}
	defer resp.Body.Close()
	raw, err := io.ReadAll(io.LimitReader(resp.Body, maxIlinkHTTPResponseBody+1))
	if err != nil {
		return nil, fmt.Errorf("weixin: %s: read body: %w", label, err)
	}
	if len(raw) > maxIlinkHTTPResponseBody {
		return nil, fmt.Errorf("weixin: %s: response body exceeds %d bytes", label, maxIlinkHTTPResponseBody)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("weixin: %s: http %d: %s", label, resp.StatusCode, truncateForLog(raw, 512))
	}
	return raw, nil
}

func truncateForLog(b []byte, max int) string {
	s := string(b)
	if len(s) <= max {
		return s
	}
	return s[:max] + "…"
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the request — the error is usually transient connection breakage
  2. Check for intermediary proxies/LBs with aggressive idle timeouts and raise them
  3. Inspect the wrapped %w error (e.g. 'unexpected EOF', 'connection reset') to identify the transport cause
  4. Ensure stable network for the host running cc-connect; log the label to know which API call failed

Example fix

// before: one-shot post
raw, err := c.post(ctx, "ilink/bot/getupdates", payload, timeout, "getUpdates")
// after: single retry on body-read failure
raw, err := c.post(ctx, "ilink/bot/getupdates", payload, timeout, "getUpdates")
if err != nil && strings.Contains(err.Error(), "read body") {
    raw, err = c.post(ctx, "ilink/bot/getupdates", payload, timeout, "getUpdates")
}
Defensive patterns

Strategy: retry

Try / catch

raw, err := c.post(ctx, ep, payload, timeout, label)
if err != nil && strings.Contains(err.Error(), "read body") {
    time.Sleep(500 * time.Millisecond)
    raw, err = c.post(ctx, ep, payload, timeout, label) // one retry
}

Prevention

When it happens

Trigger: io.ReadAll returns an error during body read — abrupt TCP reset, connection closed early by the server/proxy, or read deadline expiry mid-body.

Common situations: Server crashes or load balancer resets mid-response; proxy killing long responses; flaky mobile/hotspot networking on the host running cc-connect.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/e53ebf558f4d51bd. Report an issue: GitHub.