{"record":{"id":"1273c5c0b1da065d","repo":"chenhg5/cc-connect","slug":"range-body-length-d-requested-d","errorCode":null,"errorMessage":"range body length %d != requested %d","messagePattern":"range body length (.+?) != requested (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/resource_download.go","lineNumber":353,"sourceCode":"\t\tif resp.StatusCode == http.StatusPartialContent {\n\t\t\tcr := resp.Header.Get(\"Content-Range\")\n\t\t\tif cr != \"\" {\n\t\t\t\tif got, ok := parseContentRangeTotal(cr); ok && got != expectedTotal {\n\t\t\t\t\t_ = resp.Body.Close()\n\t\t\t\t\treturn nil, fmt.Errorf(\"Content-Range total mismatch: got %d want %d\", got, expectedTotal)\n\t\t\t\t}\n\t\t\t}\n\t\t\tbody, err := io.ReadAll(io.LimitReader(resp.Body, end-start+1+1))\n\t\t\t_ = resp.Body.Close()\n\t\t\tif err != nil {\n\t\t\t\tif isTransientError(err) && attempt < maxTransientRetries {\n\t\t\t\t\tlastErr = err\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"read range body: %w\", err)\n\t\t\t}\n\t\t\tif int64(len(body)) != end-start+1 {\n\t\t\t\treturn nil, fmt.Errorf(\"range body length %d != requested %d\", len(body), end-start+1)\n\t\t\t}\n\t\t\treturn body, nil\n\t\t}\n\n\t\t// Non-206 response: capture a snippet for diagnostics, then either\n\t\t// retry (transient 5xx) or fail fast.\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 4*1024))\n\t\t_ = resp.Body.Close()\n\n\t\tif resp.StatusCode >= 500 && resp.StatusCode < 600 && attempt < maxTransientRetries {\n\t\t\tlastErr = fmt.Errorf(\"range status %d body=%q\", resp.StatusCode, strings.TrimSpace(string(body)))\n\t\t\tcontinue\n\t\t}\n\n\t\tif resp.StatusCode >= 200 && resp.StatusCode < 300 && end-start+1 == int64(len(body)) {\n\t\t\t// Server ignored Range and returned a 200 with exactly the bytes\n\t\t\t// we wanted — fine for the last chunk of a file, slightly off for\n\t\t\t// non-tail chunks. Caller decides; we return what we got.","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/resource_download.go#L335-L371","documentation":"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.","triggerScenarios":"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.","commonSituations":"Server-side truncation of large range responses; buggy intermediary/proxy altering Content-Length; extremely large chunks hitting server body limits; transient truncation under load.","solutions":["Retry the download (short bodies are often transient); if persistent, reduce the chunk size (default 8 MiB) and retry","Bypass any HTTP proxy to rule out intermediary truncation","Check Feishu service status if a specific file consistently truncates at the same offset","Capture len(body) vs requested length in logs to identify whether truncation happens at a fixed boundary"],"exampleFix":"// before: fixed 8 MiB chunks\nchunks := int64(8 * 1024 * 1024)\n// after: fall back to smaller chunks after a short-body failure\nif strings.Contains(err.Error(), \"range body length\") {\n    chunks = 1 * 1024 * 1024 // retry with 1 MiB chunks\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := downloadResource(fileToken); err != nil && strings.Contains(err.Error(), \"range body length\") {\n    // short body: retry once with smaller chunks before giving up\n    return downloadResourceWithChunkSize(fileToken, 1<<20)\n}","preventionTips":["Keep chunk sizes moderate (8 MiB default) to reduce truncation likelihood","Bypass unreliable intermediary proxies for large range requests","Verify final file integrity with a checksum after reassembly","Track whether truncation happens at fixed byte boundaries (points to a proxy limit)"],"tags":["http","download","range-request","integrity"],"backgroundTag":"unexpected-response-shape","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}