{"record":{"id":"c1ceb519d0db1a70","repo":"chenhg5/cc-connect","slug":"max-send-message-attachment-not-ready-after-d-r","errorCode":null,"errorMessage":"max: send message: attachment not ready after %d retries","messagePattern":"max: send message: attachment not ready after (.+?) retries","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"platform/max/max.go","lineNumber":1418,"sourceCode":"\t\tresp.Body.Close()\n\n\t\tif resp.StatusCode == http.StatusOK {\n\t\t\treturn nil\n\t\t}\n\t\tif isAttachmentNotReady(respBody) && attempt < attachmentReadyRetries {\n\t\t\tslog.Debug(\"max: attachment not ready, retrying\", \"attempt\", attempt+1, \"backoff\", backoff)\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\tcase <-time.After(backoff):\n\t\t\t}\n\t\t\tbackoff *= 2\n\t\t\tcontinue\n\t\t}\n\t\tslog.Warn(\"max: send message failed\", \"status\", resp.StatusCode, \"chat\", chatID, \"body\", string(respBody))\n\t\treturn fmt.Errorf(\"max: send message: HTTP %d: %s\", resp.StatusCode, respBody)\n\t}\n\treturn fmt.Errorf(\"max: send message: attachment not ready after %d retries\", attachmentReadyRetries)\n}\n\nfunc isAttachmentNotReady(body []byte) bool {\n\treturn bytes.Contains(body, []byte(\"attachment.not.ready\")) ||\n\t\tbytes.Contains(body, []byte(\"not.ready\"))\n}\n\nfunc (p *Platform) getMe(ctx context.Context) (name string, id int64, err error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, p.apiBase+\"/me\", nil)\n\tif err != nil {\n\t\treturn \"\", 0, err\n\t}\n\tp.setAuth(req)\n\n\tresp, err := p.client.Do(req)\n\tif err != nil {\n\t\treturn \"\", 0, err\n\t}","sourceCodeStart":1400,"sourceCodeEnd":1436,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/max/max.go#L1400-L1436","documentation":"The MAX API kept responding with an 'attachment not ready' error for every attempt in the send retry loop (attachmentReadyRetries attempts with exponential backoff), so the platform gives up. MAX returns this transient error when an attachment (uploaded media) is not yet processed on its CDN.","triggerScenarios":"Sending a message with a just-uploaded attachment while MAX is still processing it, and processing takes longer than the total retry window.","commonSituations":"Large video/image uploads during MAX CDN slowness; uploading and immediately sending in the same flow; MAX service degradation making 'not ready' persist beyond the retry budget.","solutions":["Increase attachmentReadyRetries and/or the initial backoff in the retry loop","Verify the attachment upload completed (poll the upload result) before sending the message","Return a clear user-facing 'media is still processing, try again' message on this error","Check MAX service status if this happens across many sends"],"exampleFix":"// before\nreturn fmt.Errorf(\"max: send message: attachment not ready after %d retries\", attachmentReadyRetries)\n// after\nreturn fmt.Errorf(\"max: send message: attachment not ready after %d retries (consider raising attachmentReadyRetries or delay before send)\", attachmentReadyRetries)","handlingStrategy":"retry","validationCode":"if uploaded, err := pollUploadComplete(ctx, fileID); err != nil || !uploaded { delayBeforeSend() }","typeGuard":null,"tryCatchPattern":"if err := send(); err != nil && strings.Contains(err.Error(), \"attachment not ready\") {\n\ttime.Sleep(2 * time.Second)\n\terr = send() // or increase attachmentReadyRetries\n}","preventionTips":["Wait for upload/processing confirmation before sending attachment messages","Budget enough retries/backoff for large media on slow MAX days","Surface 'media processing' to users instead of failing silently"],"tags":["retries","attachments","bot-api"],"backgroundTag":"rate-limit-exceeded","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"}