{"record":{"id":"100d5e6846179167","repo":"chenhg5/cc-connect","slug":"s-cdn-response-missing-x-encrypted-param","errorCode":null,"errorMessage":"%s: CDN response missing x-encrypted-param","messagePattern":"(.+?): CDN response missing x-encrypted-param","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/weixin/cdn.go","lineNumber":216,"sourceCode":"\t\tif resp.StatusCode >= 400 && resp.StatusCode < 500 {\n\t\t\tmsg := resp.Header.Get(\"x-error-message\")\n\t\t\tif msg == \"\" {\n\t\t\t\tmsg = resp.Status\n\t\t\t}\n\t\t\treturn \"\", fmt.Errorf(\"%s: CDN upload client error %d: %s\", label, resp.StatusCode, msg)\n\t\t}\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\tmsg := resp.Header.Get(\"x-error-message\")\n\t\t\tif msg == \"\" {\n\t\t\t\tmsg = fmt.Sprintf(\"status %d\", resp.StatusCode)\n\t\t\t}\n\t\t\tlastErr = fmt.Errorf(\"%s: CDN upload server error: %s\", label, msg)\n\t\t\tslog.Warn(\"weixin: CDN upload server error\", \"label\", label, \"attempt\", attempt, \"error\", lastErr)\n\t\t\tcontinue\n\t\t}\n\t\tdl := resp.Header.Get(\"x-encrypted-param\")\n\t\tif dl == \"\" {\n\t\t\tlastErr = fmt.Errorf(\"%s: CDN response missing x-encrypted-param\", label)\n\t\t\tslog.Warn(\"weixin: CDN upload bad response\", \"label\", label, \"attempt\", attempt)\n\t\t\tcontinue\n\t\t}\n\t\treturn dl, nil\n\t}\n\tif lastErr != nil {\n\t\treturn \"\", fmt.Errorf(\"%s: CDN upload failed after %d attempts: %w\", label, cdnUploadMaxRetries, lastErr)\n\t}\n\treturn \"\", fmt.Errorf(\"%s: CDN upload failed after %d attempts\", label, cdnUploadMaxRetries)\n}\n\nfunc md5Hex(b []byte) string {\n\th := md5.Sum(b)\n\treturn hex.EncodeToString(h[:])\n}\n\nfunc detectImageMime(b []byte) string {\n\tif len(b) >= 3 && b[0] == 0xFF && b[1] == 0xD8 && b[2] == 0xFF {","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/weixin/cdn.go#L198-L234","documentation":"After a 200 OK upload response, uploadBufferToCDN requires the x-encrypted-param response header, which carries the download parameter needed for receivers to fetch the file. A 200 without this header means the CDN accepted the bytes but did not return the download handle, so the upload result is unusable. This is treated as a retryable failure (logged via slog.Warn, loop continues).","triggerScenarios":"CDN responds HTTP 200 but omits the x-encrypted-param header; typically an unexpected/changed CDN response contract or a proxy stripping response headers.","commonSituations":"WeChat iLink API version changes altering the CDN response shape; corporate proxy or middleware stripping custom x-* headers; hitting a wrong/misconfigured cdn_base endpoint that accepts uploads but speaks a different protocol.","solutions":["Verify cdn_base points at the official CDN (https://novac2c.cdn.weixin.qq.com/c2c), not a proxy that strips x-encrypted-param","Check for an updated WeChat iLink CDN contract (header renamed) and update the client","Retry — the function retries up to 3 attempts; transient edge misbehavior can omit the header","Log the full response headers on failure to confirm what the CDN actually returned"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// after upload success, verify the download param before returning\nif downloadParam == \"\" { return fmt.Errorf(\"upload ok but no download param\") }","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"missing x-encrypted-param\") {\n    // retry once; if it repeats, the CDN contract/proxy changed — alert an operator\n}","preventionTips":["Do not route CDN traffic through proxies that strip custom x-* response headers","Pin and periodically re-verify cdn_base against the official value","Log full response headers on upload to detect contract changes quickly","Subscribe to WeChat iLink API change announcements"],"tags":["cdn","upload","http-headers","weixin","unexpected-response"],"backgroundTag":"unexpected-api-response-shape","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"}