{"record":{"id":"fb5efae879de2d52","repo":"chenhg5/cc-connect","slug":"build-request-w","errorCode":null,"errorMessage":"build request: %w","messagePattern":"build request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/resource_download.go","lineNumber":257,"sourceCode":"\treturn n, true\n}\n\n// resourceURL builds the Feishu message-resource endpoint URL. Feishu\n// serves this on the same base URL as the rest of the API; we use the\n// configured domain so Lark international deployments also work.\nfunc (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","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/resource_download.go#L239-L275","documentation":"resourceSingleGet builds the HTTP GET request for the Feishu resource endpoint with http.NewRequestWithContext; if request construction fails (malformed URL, invalid method/context), the error is wrapped as \"build request\". This path is used for small files and as a fallback when the chunked size probe fails.","triggerScenarios":"p.resourceURL(messageID, fileKey, resType) returns a URL that http.NewRequestWithContext cannot parse — empty or malformed message_id/file_key, characters needing escaping (control chars, spaces) embedded in the file key, or a misconfigured base URL.","commonSituations":"fileKey extracted from a message contains unexpected characters or is empty because the message metadata was parsed incorrectly; base URL misconfigured in a self-hosted/proxy setup; resType misspelled by a caller constructing the URL path.","solutions":["Inspect the wrapped cause (%w) — url.Parse errors name the exact malformed part of the URL","Log and validate messageID and fileKey before calling the download; ensure they come from a properly parsed Feishu message","Check p.resourceURL / base URL configuration for typos or missing scheme","Reject empty fileKey/messageID early instead of letting them produce an invalid URL"],"exampleFix":"// before\ndata, err := p.resourceSingleGet(ctx, token, msgID, fileKey, resType)\n// after: validate inputs first\nif msgID == \"\" || fileKey == \"\" {\n    return nil, fmt.Errorf(\"feishu: invalid message_id=%q file_key=%q\", msgID, fileKey)\n}\ndata, err := p.resourceSingleGet(ctx, token, msgID, fileKey, resType)","handlingStrategy":"validation","validationCode":"func validResourceInputs(msgID, fileKey string) bool {\n    return msgID != \"\" && fileKey != \"\" && !strings.ContainsFunc(fileKey, func(r rune) bool { return r < 0x21 || r == '%' })\n}\n// call before download\nif !validResourceInputs(msgID, fileKey) { return fmt.Errorf(\"invalid resource identifiers\") }","typeGuard":null,"tryCatchPattern":"data, err := p.resourceSingleGet(ctx, token, msgID, fileKey, resType)\nif err != nil {\n    if strings.Contains(err.Error(), \"build request\") {\n        return nil, fmt.Errorf(\"invalid resource URL inputs: %w\", err)\n    }\n    return nil, err\n}","preventionTips":["Validate message_id and file_key as non-empty, URL-safe strings before download","Parse file_key out of message metadata with strict checks","Keep the Feishu base URL configuration correct and scheme-complete"],"tags":["http","url","request-construction","feishu"],"backgroundTag":"invalid-url","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"}