{"record":{"id":"6e3895b7c8e11600","repo":"chenhg5/cc-connect","slug":"max-upload-image-w","errorCode":null,"errorMessage":"max: upload image: %w","messagePattern":"max: upload image: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/max/max.go","lineNumber":424,"sourceCode":"\t\t\t\tType:    \"callback\",\n\t\t\t\tText:    btn.Text,\n\t\t\t\tPayload: btn.Data,\n\t\t\t})\n\t\t}\n\t\tmaxButtons = append(maxButtons, maxRow)\n\t}\n\treturn p.sendText(ctx, replyCtx, content, maxButtons)\n}\n\n// SendImage implements core.ImageSender.\nfunc (p *Platform) SendImage(ctx context.Context, replyCtx any, img core.ImageAttachment) error {\n\trctx, ok := replyCtx.(replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"max: unexpected replyCtx type %T\", replyCtx)\n\t}\n\ttoken, err := p.uploadAttachment(ctx, \"image\", img.Data, img.FileName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"max: upload image: %w\", err)\n\t}\n\tbody := &maxSendBody{\n\t\tAttachments: []maxOutAttachment{{\n\t\t\tType:    \"image\",\n\t\t\tPayload: maxTokenPayload{Token: token},\n\t\t}},\n\t}\n\treturn p.postMessage(ctx, rctx.chatID, body)\n}\n\n// SendFile implements core.FileSender. MAX routes images uploaded via the file\n// endpoint as type=\"file\" in the message, so we honor the declared kind: if the\n// mime says image/*, we upload as image so the recipient sees a proper image\n// preview instead of a generic file card.\nfunc (p *Platform) SendFile(ctx context.Context, replyCtx any, file core.FileAttachment) error {\n\trctx, ok := replyCtx.(replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"max: unexpected replyCtx type %T\", replyCtx)","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/max/max.go#L406-L442","documentation":"Wrapped failure from uploadAttachment when sending an image: the MAX platform's attachment upload API call failed, so no attachment token was obtained to reference in the outgoing message body.","triggerScenarios":"SendImage called with empty/oversized img.Data, unsupported format, network failure to the upload endpoint, or an HTTP >= 300 from the upload API (often 401 with an invalid token).","commonSituations":"Expired bot token invalidating uploads, file exceeding MAX's size limit, transient network errors, wrong FileName/MIME causing rejection.","solutions":["Check the wrapped upload error: HTTP 401/403 → fix the token; 413 → shrink the image.","Verify img.Data is a complete, non-empty image payload and FileName has a proper extension.","Retry on transient network/5xx errors; uploads are idempotent since no message was sent.","Log the response body (wrapped in the error) for the API's specific rejection reason."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if len(img.Data) == 0 { return errors.New(\"empty image data\") }\nif len(img.Data) > maxUploadBytes { return fmt.Errorf(\"image exceeds %d bytes\", maxUploadBytes) }","typeGuard":null,"tryCatchPattern":"if err := p.SendImage(ctx, replyCtx, img); err != nil {\n    if strings.Contains(err.Error(), \"upload image\") {\n        if isRetryable(err) { // 5xx or network\n            retryWithBackoff(func() error { return p.SendImage(ctx, replyCtx, img) })\n        } else {\n            slog.Error(\"image upload rejected\", \"err\", err)\n        }\n    }\n}","preventionTips":["Validate image size and data completeness before sending","Use file names with proper image extensions","Refresh tokens before long send operations","Cap retries for transient errors; never retry 4xx rejections"],"tags":["go","upload","http"],"backgroundTag":"api-request-failed","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"}