chenhg5/cc-connect · error

read range body: %w

Error message

read range body: %w

What it means

After receiving a 206 Partial Content response, resourceRangeChunk reads exactly the requested number of bytes (end-start+1 plus one sentinel byte). If io.ReadAll fails mid-read (connection reset, context cancellation, decompression error), the error is wrapped as 'read range body' and returned after transient errors are exhausted.

Source

Thrown at platform/feishu/resource_download.go:350

			return nil, fmt.Errorf("range request: %w", err)
		}

		if resp.StatusCode == http.StatusPartialContent {
			cr := resp.Header.Get("Content-Range")
			if cr != "" {
				if got, ok := parseContentRangeTotal(cr); ok && got != expectedTotal {
					_ = resp.Body.Close()
					return nil, fmt.Errorf("Content-Range total mismatch: got %d want %d", got, expectedTotal)
				}
			}
			body, err := io.ReadAll(io.LimitReader(resp.Body, end-start+1+1))
			_ = resp.Body.Close()
			if err != nil {
				if isTransientError(err) && attempt < maxTransientRetries {
					lastErr = err
					continue
				}
				return nil, fmt.Errorf("read range body: %w", err)
			}
			if int64(len(body)) != end-start+1 {
				return nil, fmt.Errorf("range body length %d != requested %d", len(body), end-start+1)
			}
			return body, nil
		}

		// Non-206 response: capture a snippet for diagnostics, then either
		// retry (transient 5xx) or fail fast.
		body, _ := io.ReadAll(io.LimitReader(resp.Body, 4*1024))
		_ = resp.Body.Close()

		if resp.StatusCode >= 500 && resp.StatusCode < 600 && attempt < maxTransientRetries {
			lastErr = fmt.Errorf("range status %d body=%q", resp.StatusCode, strings.TrimSpace(string(body)))
			continue
		}

		if resp.StatusCode >= 200 && resp.StatusCode < 300 && end-start+1 == int64(len(body)) {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the download; transient read errors are auto-retried up to maxTransientRetries, so persistent failures usually indicate network instability
  2. Reduce chunk size so each range request completes faster and is less exposed to mid-body drops
  3. Check proxy/firewall/VPN stability between the client and Feishu APIs
  4. Inspect the wrapped cause (%w) for context deadline vs connection reset to target the right fix
Defensive patterns

Strategy: retry

Validate before calling

// pre-check connectivity to the API host before long downloads
conn, err := net.DialTimeout("tcp", "open.feishu.cn:443", 3*time.Second)
if err != nil { return fmt.Errorf("feishu unreachable: %w", err) }
conn.Close()

Try / catch

if err := downloadResource(fileToken); err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) || strings.Contains(err.Error(), "read range body") {
        // transient network issue: retry with backoff
    }
}

Prevention

When it happens

Trigger: resourceFetchRemainingChunks -> resourceRangeChunk: the HTTP GET with a Range header returns 206 but the body read fails — network interruption mid-body, server closes connection early, TLS error, or context deadline exceeded during read, after isTransientError retry attempts are used up or the error is non-transient.

Common situations: Unstable network/proxy dropping long-running downloads; corporate proxy resetting connections on large bodies; Feishu server closing keep-alive connections; client-side context cancellation.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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