{"record":{"id":"01cea7115f24733e","repo":"chenhg5/cc-connect","slug":"resource-size-mismatch-assembled-d-expected-d","errorCode":null,"errorMessage":"resource size mismatch: assembled=%d expected=%d","messagePattern":"resource size mismatch: assembled=(.+?) expected=(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/resource_download.go","lineNumber":214,"sourceCode":"\tchunks := 1 // count the first byte we already have\n\tfor offset := int64(1); offset < total; offset += chunkSize {\n\t\tend := offset + chunkSize - 1\n\t\tif end >= total {\n\t\t\tend = total - 1\n\t\t}\n\t\tn, err := p.resourceRangeChunk(ctx, token, messageID, fileKey, resType, offset, end, total)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"resource chunk offset=%d: %w\", offset, err)\n\t\t}\n\t\tbuf.Write(n)\n\t\tchunks++\n\t\tif err := ctx.Err(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif int64(buf.Len()) != total {\n\t\treturn nil, fmt.Errorf(\"resource size mismatch: assembled=%d expected=%d\", buf.Len(), total)\n\t}\n\tslog.Info(p.tag()+\": resource chunked download complete\",\n\t\t\"file_key\", fileKey, \"type\", resType, \"total\", total, \"chunks\", chunks,\n\t\t\"chunk_size\", chunkSize)\n\treturn buf.Bytes(), nil\n}\n\n// parseContentRangeTotal extracts the \"total\" field from a Content-Range\n// header of the form \"bytes 0-0/12345\". Returns false if the header is\n// malformed or uses a unit we don't recognise.\nfunc parseContentRangeTotal(h string) (int64, bool) {\n\th = strings.TrimSpace(h)\n\tslash := strings.LastIndex(h, \"/\")\n\tif slash < 0 || slash == len(h)-1 {\n\t\treturn 0, false\n\t}\n\ttotalStr := strings.TrimSpace(h[slash+1:])\n\tif totalStr == \"*\" {","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/resource_download.go#L196-L232","documentation":"After fetching all chunks in resourceFetchRemainingChunks, the library verifies that the assembled buffer length equals the total size reported by the initial size probe (Content-Range total). If they differ, the download is inconsistent — some chunk came back short or the server returned fewer bytes than promised — and the library discards the data and returns this error rather than delivering a corrupt file.","triggerScenarios":"A Range chunk returns fewer bytes than requested (end-start+1) without an error; the probed total from the size probe changed server-side between probe and download (file replaced mid-download); a chunk response includes unexpected body length while still being status 206.","commonSituations":"File was modified or deleted on the Feishu server between the size probe and the chunk downloads; a proxy truncated a chunk body; server-side rate limiting caused an incomplete but non-error chunk response; concurrent re-upload of the same message resource.","solutions":["Retry the whole download — the size probe runs again, so a transient truncation usually resolves","Confirm the message/file_key still refers to an unchanged resource; re-request the file from the sender if it was replaced","Check for proxies/middleboxes that can truncate HTTP responses and bypass them","If it persists, fall back to resourceSingleGet for the resource (bypass chunk assembly) if the size permits","Log the wrapped sizes (assembled vs expected) and compare with the server's Content-Range totals to identify which chunk was short"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"data, err := p.resourceDownloadStream(ctx, token, msgID, fileKey, resType)\nif err != nil {\n    var sizeErr = \"resource size mismatch\"\n    if strings.Contains(err.Error(), sizeErr) {\n        // re-run: the size probe re-executes, recovering from a changed file\n        return p.resourceDownloadStream(ctx, token, msgID, fileKey, resType)\n    }\n    return err\n}","preventionTips":["Retry mismatched downloads once — the probe re-runs against current file state","Avoid re-uploading/replacing a file resource while it is being downloaded","Bypass proxies that can truncate response bodies"],"tags":["data-integrity","chunked-download","size-mismatch","feishu"],"backgroundTag":"checksum-mismatch","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}