{"record":{"id":"0a2677c03db10ba0","repo":"chenhg5/cc-connect","slug":"qqbot-api-s-s-returned-d-s","errorCode":null,"errorMessage":"qqbot: api %s %s returned %d: %s","messagePattern":"qqbot: api (.+?) (.+?) returned (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":370,"sourceCode":"\t\t\treturn fmt.Errorf(\"qqbot: api retry failed: %w\", err)\n\t\t}\n\t\tdefer resp2.Body.Close()\n\n\t\tif resp2.StatusCode >= 300 {\n\t\t\traw, _ := io.ReadAll(resp2.Body)\n\t\t\treturn fmt.Errorf(\"qqbot: api %s %s returned %d (after retry): %s\", method, url, resp2.StatusCode, raw)\n\t\t}\n\t\tif result != nil {\n\t\t\tif err := json.NewDecoder(resp2.Body).Decode(result); err != nil {\n\t\t\t\treturn fmt.Errorf(\"qqbot: decode response: %w\", err)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\tif resp.StatusCode >= 300 {\n\t\traw, _ := io.ReadAll(resp.Body)\n\t\treturn fmt.Errorf(\"qqbot: api %s %s returned %d: %s\", method, url, resp.StatusCode, raw)\n\t}\n\tif result != nil {\n\t\tif err := json.NewDecoder(resp.Body).Decode(result); err != nil {\n\t\t\treturn fmt.Errorf(\"qqbot: decode response: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nvar _ core.ImageSender = (*Platform)(nil)\n\n// buttonDataPrefix is the prefix for QQ Bot keyboard button_data values.\n// Format: perm:<decision>:<session_key>\nconst buttonDataPrefix = \"perm:\"\n\n// SendFile uploads and sends a file via QQ Bot rich media API.\n// Implements core.FileSender.\nfunc (p *Platform) SendFile(ctx context.Context, replyCtx any, file core.FileAttachment) error {","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L352-L388","documentation":"On the normal (non-401) path, when the QQ API responds with an HTTP status >= 300, apiRequestJSON returns this error containing the method, URL, status code, and the raw response body. This is the primary API-error surface for qqbot: 400 validation errors, 401 auth failures (before retry), 403 permission, 413 oversized media, and 429 rate limits all surface here.","triggerScenarios":"sendMessage, uploadRichMedia, or ackInteraction receives resp.StatusCode >= 300 from the QQ API on the first attempt — invalid message payload, expired msg_id reuse, bot not in the target group, oversized upload, or rate limiting.","commonSituations":"Reusing an event msg_id more than allowed (QQ dedup rule); sending to a group the bot was removed from; media exceeding size limits; exceeding per-message msg_seq constraints; API downtime returning 5xx.","solutions":["Parse the raw body included in the error — QQ error codes identify the exact problem.","429: implement/exercise backoff; check msg_seq incrementing via nextMsgSeq.","404/400 with openID: verify the bot is in the group and the openID is from the same app.","413 on upload: shrink the file before calling SendImage/SendFile.","Check QQ Open Platform status page for ongoing incidents on 5xx.","Read the raw body in the error message — the QQ API error code explains the cause (e.g. 11253 rate limit, invalid openID)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if len(data) > maxUploadBytes {\n    return fmt.Errorf(\"attachment too large for qqbot: %d bytes\", len(data))\n}\nif rctx.GroupOpenID == \"\" && rctx.UserOpenID == \"\" {\n    return fmt.Errorf(\"no target openID for qqbot send\")\n}","typeGuard":null,"tryCatchPattern":"if err := p.SendImage(ctx, rctx, img); err != nil {\n    var status int\n    if _, sErr := fmt.Sscanf(err.Error(), \"qqbot: api %*s %*s returned %d\", &status); sErr == nil && status == 429 {\n        time.Sleep(rateLimitBackoff)\n        return p.SendImage(ctx, rctx, img) // bounded retry\n    }\n    return err\n}","preventionTips":["Check the raw response body in the error for QQ error codes before deciding to retry.","Respect rate limits; back off on 429.","Pre-validate payload sizes and openIDs before API calls.","Track QQ Open Platform status for 5xx incidents.","Read the raw body in the error message — the QQ API error code explains the cause (e.g. 11253 rate limit, invalid openID)."],"tags":["qqbot","http","api"],"backgroundTag":"http-error-response","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"}