{"record":{"id":"db934182ae3655a5","repo":"chenhg5/cc-connect","slug":"read-resource-w","errorCode":null,"errorMessage":"read resource: %w","messagePattern":"read resource: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/resource_download.go","lineNumber":280,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"resource request: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 4*1024))\n\t\treturn nil, fmt.Errorf(\"resource API status=%d body=%q\", resp.StatusCode, strings.TrimSpace(string(body)))\n\t}\n\n\tif cl := resp.ContentLength; cl > p.resourceMaxBytes {\n\t\treturn nil, fmt.Errorf(\"resource too large: Content-Length=%d exceeds cap %d\", cl, p.resourceMaxBytes)\n\t}\n\n\t// LimitReader caps the body too in case the server lies about\n\t// Content-Length; we read up to cap+1 bytes to detect the lie.\n\tdata, err := io.ReadAll(io.LimitReader(resp.Body, p.resourceMaxBytes+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read resource: %w\", err)\n\t}\n\tif int64(len(data)) > p.resourceMaxBytes {\n\t\treturn nil, fmt.Errorf(\"resource too large: body exceeds cap %d\", p.resourceMaxBytes)\n\t}\n\tslog.Debug(p.tag()+\": resource downloaded (single GET)\",\n\t\t\"file_key\", fileKey, \"type\", resType, \"size\", len(data))\n\treturn data, nil\n}\n\n// resourceRangeChunk fetches a single byte range and verifies the\n// Content-Range header agrees with what we asked for. Returns the bytes\n// received; caller is responsible for ordering into the final buffer.\n//\n// Transient errors are retried with backoff; non-transient errors (4xx, 5xx\n// other than the documented transient cases) fail fast.\nfunc (p *Platform) resourceRangeChunk(\n\tctx context.Context,\n\ttoken, messageID, fileKey, resType string,","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/resource_download.go#L262-L298","documentation":"io.ReadAll on the resource response body failed while reading the file content in resourceSingleGet (wrapped as \"read resource\"). This is a mid-body I/O error: connection reset, unexpected EOF, context cancellation, or a proxy truncating the stream.","triggerScenarios":"resourceSingleGet got a 2xx response, passed the Content-Length check, but the body read failed — server closed the connection mid-transfer, ctx was cancelled, TLS/connection error mid-stream, or a proxy dropped the connection.","commonSituations":"Unstable network on long transfers; idle-connection timeouts or LB/proxy read timeouts cutting off a slow body; ctx deadline expiring while reading a large body; Feishu edge closing connections under load.","solutions":["Retry the download — transient mid-body failures usually succeed on a second attempt","Inspect the wrapped cause: context.DeadlineExceeded → increase ctx timeout; unexpected EOF → network/proxy issue","Disable aggressive idle timeouts on proxies/LBs in front of egress, or raise their read timeout","Ensure the HTTP client transport sets sensible timeouts (ResponseHeaderTimeout vs overall) so slow bodies aren't cut off","For large files prefer the chunked path, which retries transient errors per chunk"],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n// after: allow time for large bodies\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"data, err := p.resourceSingleGet(ctx, token, msgID, fileKey, resType)\nif err != nil {\n    if strings.Contains(err.Error(), \"read resource:\") {\n        return backoffRetry(ctx, 3, download) // transient mid-body IO error\n    }\n    return err\n}","preventionTips":["Use generous context timeouts proportional to file size","Configure transport keep-alives and avoid aggressive proxy read timeouts","Retry mid-body failures automatically with exponential backoff"],"tags":["network","http","io","feishu"],"backgroundTag":"network-request-failed","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"}