{"record":{"id":"53b3fe4fe5e1a221","repo":"chenhg5/cc-connect","slug":"empty-url","errorCode":null,"errorMessage":"empty url","messagePattern":"empty url","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/max/max.go","lineNumber":1184,"sourceCode":"\t\t\t\treturn sub\n\t\t\t}\n\t\t}\n\t}\n\tif filename != \"\" {\n\t\tif i := strings.LastIndex(filename, \".\"); i >= 0 && i < len(filename)-1 {\n\t\t\treturn strings.ToLower(filename[i+1:])\n\t\t}\n\t}\n\treturn \"ogg\"\n}\n\n// downloadAttachment GETs an arbitrary URL (typically a pre-signed CDN link\n// from MAX), capping the response at maxAttachmentBytes. The URLs MAX serves\n// for image/file payloads are already authenticated, so no bot token is\n// attached to the request.\nfunc (p *Platform) downloadAttachment(ctx context.Context, url string) ([]byte, string, error) {\n\tif url == \"\" {\n\t\treturn nil, \"\", fmt.Errorf(\"empty url\")\n\t}\n\tdlCtx, cancel := context.WithTimeout(ctx, attachmentDownloadTO)\n\tdefer cancel()\n\treq, err := http.NewRequestWithContext(dlCtx, http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tresp, err := p.client.Do(req)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, \"\", fmt.Errorf(\"HTTP %d\", resp.StatusCode)\n\t}\n\tdata, err := io.ReadAll(io.LimitReader(resp.Body, maxAttachmentBytes+1))\n\tif err != nil {\n\t\treturn nil, \"\", err","sourceCodeStart":1166,"sourceCodeEnd":1202,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/max/max.go#L1166-L1202","documentation":"downloadAttachment refuses to issue an HTTP GET when the supplied URL is the empty string. The URL is normally a pre-signed CDN link taken from a MAX message payload; an empty value means the payload never contained one.","triggerScenarios":"A MAX image/file message arrives whose attachment object has an empty url field and the platform calls downloadAttachment with that value directly.","commonSituations":"Processing message types that carry attachments without download URLs (e.g. stickers, voice handled via tokens instead of URLs); MAX API change removing the url field; upstream sender sending malformed attachments.","solutions":["Check url != \"\" (or validate the attachment object) before calling downloadAttachment","Use resolveMediaURL for video/audio attachments that only provide a token","Log the raw attachment JSON when the URL is missing to identify the message type","Skip or placeholder the attachment in the outgoing message instead of failing"],"exampleFix":"// before\ndata, ct, err := p.downloadAttachment(ctx, att.URL)\n// after\nif att.URL == \"\" {\n\treturn skipAttachment(att)\n}\ndata, ct, err := p.downloadAttachment(ctx, att.URL)","handlingStrategy":"validation","validationCode":"if url == \"\" { return skipOrPlaceholder(attachment) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate attachment URL/token presence when parsing incoming MAX messages","Log raw attachment JSON for payloads lacking URLs","Route video/audio through resolveMediaURL instead of downloadAttachment"],"tags":["validation","attachments","bot-api"],"backgroundTag":"empty-required-field","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"}