chenhg5/cc-connect · error

range request: %w

Error message

range request: %w

What it means

The HTTP Range request for a chunk failed at the transport level and the error was not classified as transient (or retries were exhausted), so resourceRangeChunk gives up and wraps it as "range request". Transient errors are already retried internally up to maxTransientRetries before this error surfaces.

Source

Thrown at platform/feishu/resource_download.go:332

		}

		req, err := http.NewRequestWithContext(ctx, http.MethodGet,
			p.resourceURL(messageID, fileKey, resType), nil)
		if err != nil {
			return nil, fmt.Errorf("build range request: %w", err)
		}
		req.Header.Set("Authorization", "Bearer "+token)
		req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end))

		resp, err := p.resourceDownloadHTTP.Do(req)
		if err != nil {
			if isTransientError(err) && attempt < maxTransientRetries {
				lastErr = err
				slog.Debug(p.tag()+": transient range chunk error; retrying",
					"attempt", attempt, "error", err, "start", start, "end", end)
				continue
			}
			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)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the whole resourceDownloadStream after checking connectivity — per-chunk retries were exhausted
  2. Inspect the wrapped cause to classify it: connection refused (server/proxy down), timeout (raise timeouts), context cancelled (look for upstream cancellation)
  3. Increase maxTransientRetries or add backoff at the download-stream level for flaky networks
  4. Verify egress to open.feishu.cn and that proxies keep connections alive long enough for each chunk
  5. Ensure the ctx passed in isn't being cancelled early by a parent (e.g. message-handling timeout too short for large files)

Example fix

// before: short-lived context from message handler
ctx, cancel := context.WithTimeout(parentCtx, 10*time.Second)
// after: budget proportional to file size
ctx, cancel := context.WithTimeout(parentCtx, 2*time.Minute)
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: confirm reachability before a long chunked download
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, "https://open.feishu.cn", nil)
if _, err := http.DefaultClient.Do(req); err != nil {
    return fmt.Errorf("feishu unreachable, defer download: %w", err)
}

Try / catch

data, err := p.resourceDownloadStream(ctx, token, msgID, fileKey, resType)
if err != nil {
    if strings.Contains(err.Error(), "range request:") {
        // per-chunk retries exhausted; retry the whole download with longer backoff
        return backoffRetry(ctx, 3, wholeDownload)
    }
    return err
}

Prevention

When it happens

Trigger: p.resourceDownloadHTTP.Do fails for a chunk GET — connection reset/refused, TLS handshake error, ctx cancellation/timeout — and isTransientError returns false (or the retry budget maxTransientRetries is spent on repeated transient errors).

Common situations: Sustained network outage during a long multi-chunk download; proxy/LB killing long-lived connections; token refresh goroutine cancelled the ctx mid-download; DNS flaps; retries exhausted during a Feishu incident.

Related errors


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