chenhg5/cc-connect · error

range body length %d != requested %d

Error message

range body length %d != requested %d

What it means

After a successful 206 read, resourceRangeChunk verifies that the number of bytes read equals the requested range length (end-start+1). A short (or over-long) body means the server did not honor the exact byte range, so continuing would corrupt the reassembled file; the error aborts the chunk download.

Source

Thrown at platform/feishu/resource_download.go:353

		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)) {
			// Server ignored Range and returned a 200 with exactly the bytes
			// we wanted — fine for the last chunk of a file, slightly off for
			// non-tail chunks. Caller decides; we return what we got.

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the download (short bodies are often transient); if persistent, reduce the chunk size (default 8 MiB) and retry
  2. Bypass any HTTP proxy to rule out intermediary truncation
  3. Check Feishu service status if a specific file consistently truncates at the same offset
  4. Capture len(body) vs requested length in logs to identify whether truncation happens at a fixed boundary

Example fix

// before: fixed 8 MiB chunks
chunks := int64(8 * 1024 * 1024)
// after: fall back to smaller chunks after a short-body failure
if strings.Contains(err.Error(), "range body length") {
    chunks = 1 * 1024 * 1024 // retry with 1 MiB chunks
}
Defensive patterns

Strategy: retry

Try / catch

if err := downloadResource(fileToken); err != nil && strings.Contains(err.Error(), "range body length") {
    // short body: retry once with smaller chunks before giving up
    return downloadResourceWithChunkSize(fileToken, 1<<20)
}

Prevention

When it happens

Trigger: resourceFetchRemainingChunks -> resourceRangeChunk: response is 206 but io.LimitReader yielded len(body) != end-start+1 — server returned fewer/more bytes than the requested range despite the 206 status.

Common situations: Server-side truncation of large range responses; buggy intermediary/proxy altering Content-Length; extremely large chunks hitting server body limits; transient truncation under load.

Related errors


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