{"record":{"id":"9b5e8a4b60e862b0","repo":"chenhg5/cc-connect","slug":"build-first-chunk-request-w","errorCode":null,"errorMessage":"build first-chunk request: %w","messagePattern":"build first-chunk request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/resource_download.go","lineNumber":143,"sourceCode":"\t// Server honoured Range. Loop the remaining chunks.\n\tif total > p.resourceMaxBytes {\n\t\treturn nil, fmt.Errorf(\"resource too large: total=%d exceeds cap %d\", total, p.resourceMaxBytes)\n\t}\n\tif int64(len(first)) >= total {\n\t\t// Defensive: a server that advertises 206 with first slice already\n\t\t// covering the whole resource is fine — return what we have.\n\t\treturn first, nil\n\t}\n\treturn p.resourceFetchRemainingChunks(ctx, token, messageID, fileKey, resType, total, first)\n}\n\n// resourceFetchFirstChunk issues Range bytes=0-0 to learn the total and grab\n// the first byte. Returns (first, total, nil) where total==0 means the\n// server ignored Range and the entire body is in `first`.\nfunc (p *Platform) resourceFetchFirstChunk(ctx context.Context, token, messageID, fileKey, resType string) ([]byte, int64, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, p.resourceURL(messageID, fileKey, resType), nil)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"build first-chunk request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+token)\n\treq.Header.Set(\"Range\", \"bytes=0-0\")\n\n\tresp, err := p.resourceDownloadHTTP.Do(req)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"first-chunk request: %w\", err)\n\t}\n\tdefer func() { _, _ = io.Copy(io.Discard, resp.Body); _ = resp.Body.Close() }()\n\n\tswitch resp.StatusCode {\n\tcase http.StatusPartialContent:\n\t\tcr := resp.Header.Get(\"Content-Range\")\n\t\ttotal, ok := parseContentRangeTotal(cr)\n\t\tif !ok {\n\t\t\treturn nil, 0, fmt.Errorf(\"first-chunk: 206 without parseable Content-Range %q\", cr)\n\t\t}\n\t\tbody, err := io.ReadAll(io.LimitReader(resp.Body, 1))","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/resource_download.go#L125-L161","documentation":"Wraps http.NewRequestWithContext failure while building the Range bytes=0-0 probe request in resourceFetchFirstChunk. With a static URL template this essentially only fails on a malformed URL (e.g. invalid characters in messageID/fileKey or a bad domain), or a nil/invalid context. Note: when this fires, the caller resourceDownloadStream falls back to resourceSingleGet, which will also fail to build its request.","triggerScenarios":"http.NewRequestWithContext returns an error, typically from url.Parse on p.resourceURL(...) output — e.g. a domain configured with invalid characters, or messageID/fileKey containing control characters that were not validated upstream.","commonSituations":"Misconfigured Feishu domain in config.toml (e.g. contains a space or newline), or a malformed message_id/file_key passed from an upstream envelope without validation.","solutions":["Validate the configured domain (open.feishu.cn / open.larksuite.com) for stray whitespace or invalid characters","Ensure messageID/fileKey are validated (non-empty, no control characters) before download","Check the wrapped error (%w) for the exact url.Parse message identifying the bad component"],"exampleFix":"// before\ndomain = \"https://open.feishu.cn/ \"\n// after\ndomain = \"https://open.feishu.cn\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(fmt.Sprintf(\"%s/open-apis/im/v1/messages/%s/resources/%s\", domain, msgID, key)); if err != nil { return err }","typeGuard":"null","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"build first-chunk request\") {\n    return fmt.Errorf(\"malformed resource URL (check domain/messageID/fileKey): %w\", err)\n}","preventionTips":["Trim whitespace from the configured domain at config load time","Validate messageID/fileKey are opaque tokens without control characters or '/'","Add a config-load check that parses a sample resource URL","Never interpolate raw user text into URL path segments without escaping"],"tags":["go","feishu","http","url"],"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"}