{"record":{"id":"56979f4ccfeef5c2","repo":"chenhg5/cc-connect","slug":"resource-request-w","errorCode":null,"errorMessage":"resource request: %w","messagePattern":"resource request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/resource_download.go","lineNumber":263,"sourceCode":"func (p *Platform) resourceURL(messageID, fileKey, resType string) string {\n\treturn fmt.Sprintf(\"%s/open-apis/im/v1/messages/%s/resources/%s?type=%s\",\n\t\tstrings.TrimRight(p.domain, \"/\"), messageID, fileKey, resType)\n}\n\n// resourceSingleGet downloads the entire resource with one plain GET. Used\n// for small files and as a fallback when the size probe fails. We honour\n// resourceMaxBytes via Content-Length + body cap so a misbehaving server\n// can't blow up memory.\nfunc (p *Platform) resourceSingleGet(ctx context.Context, token, messageID, fileKey, resType string) ([]byte, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, p.resourceURL(messageID, fileKey, resType), nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"build request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+token)\n\n\tresp, err := p.resourceDownloadHTTP.Do(req)\n\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}","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/resource_download.go#L245-L281","documentation":"The HTTP request issued by resourceSingleGet failed at the transport level: p.resourceDownloadHTTP.Do returned an error (DNS failure, connection refused/reset, TLS error, context cancellation/timeout). The library wraps it as \"resource request\" so callers know the failure happened while contacting the Feishu resource endpoint.","triggerScenarios":"Calling resourceDownloadStream for a small file (or when the size probe fails) triggers resourceSingleGet; the GET to the resource URL fails before a response is received — no network, DNS failure, proxy error, TLS problem, or the ctx deadline expires mid-request.","commonSituations":"No internet access or DNS resolution failing in the deployment environment; corporate proxy not configured for the resourceDownloadHTTP client; context timeout too short for large files on slow links; firewall blocking egress to open.feishu.cn.","solutions":["Inspect the wrapped cause (%w): net.Error timeouts suggest increasing the HTTP client timeout or ctx deadline; connection errors suggest network/proxy problems","Verify egress connectivity to the Feishu API host (curl the resource URL host from the deployment machine)","Configure proxy environment variables / a custom http.Transport on resourceDownloadHTTP if behind a proxy","If the cause is context.DeadlineExceeded, increase the timeout passed via ctx for large-file downloads","Retry — resourceDownloadStream callers may recover from transient network errors"],"exampleFix":"// before: default client, no timeout tuning\nresp, err := p.resourceDownloadHTTP.Do(req)\n// after: dedicated transport with sane timeouts\np.resourceDownloadHTTP = &http.Client{\n    Timeout: 5 * time.Minute,\n    Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},\n}","handlingStrategy":"retry","validationCode":"// pre-flight connectivity check\nresp, err := http.Get(\"https://open.feishu.cn/open-apis\")\nif err != nil { log.Warn(\"feishu unreachable\", \"err\", err) } else { resp.Body.Close() }","typeGuard":null,"tryCatchPattern":"data, err := p.resourceSingleGet(ctx, token, msgID, fileKey, resType)\nif err != nil {\n    if strings.Contains(err.Error(), \"resource request:\") {\n        if errors.Is(ctx.Err(), context.DeadlineExceeded) {\n            // increase timeout and retry once\n        }\n        return backoffRetry(ctx, 3, download)\n    }\n    return err\n}","preventionTips":["Set explicit timeouts on the resourceDownloadHTTP client and context","Configure proxy settings (HTTP_PROXY/HTTPS_PROXY) in restricted environments","Monitor egress connectivity/DNS health in the deployment environment"],"tags":["network","http","timeout","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"}