{"record":{"id":"2485a81c9688b199","repo":"chenhg5/cc-connect","slug":"qqbot-api-s-s-returned-d-after-retry-s","errorCode":null,"errorMessage":"qqbot: api %s %s returned %d (after retry): %s","messagePattern":"qqbot: api (.+?) (.+?) returned (.+?) \\(after retry\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":358,"sourceCode":"\t\t\tdata, _ := json.Marshal(body)\n\t\t\tbodyReader = bytes.NewReader(data)\n\t\t}\n\t\treq2, err := http.NewRequest(method, url, bodyReader)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"qqbot: build retry request: %w\", err)\n\t\t}\n\t\treq2.Header.Set(\"Authorization\", \"QQBot \"+token)\n\t\treq2.Header.Set(\"Content-Type\", \"application/json\")\n\n\t\tresp2, err := core.HTTPClient.Do(req2)\n\t\tif err != nil {\n\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}","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L340-L376","documentation":"After the 401 retry, if the second response still has an HTTP status >= 300, apiRequestJSON returns this error including the method, URL, status code, and the raw response body. It means the token refresh did not fix the authorization problem, or a non-auth error (400/403/404/413/429) occurred on the retried call.","triggerScenarios":"The first attempt got 401, refresh + retry succeeded at transport level, but resp2.StatusCode >= 300 — e.g. still 401 (bad credentials), 403 (no permission for that group/user), 404 (bad openID), 413 (file too large), or 429 (rate limited).","commonSituations":"Wrong or revoked appSecret surviving a refresh; bot not added to the target group; invalid file_type/file size on rich media upload; exceeding QQ message rate limits.","solutions":["Read the raw body in the error message — the QQ API error code explains the cause (e.g. 11253 rate limit, invalid openID).","Still 401 after retry: re-verify appId/appSecret in config.toml; restart to force fresh tokens.","403/404: confirm the bot is a member of the target group and the openID matches an existing chat.","413: reduce file size to QQ Bot rich media limits before uploading.","429: back off and retry later; check nextMsgSeq/msg_id reuse."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if len(fileData) > maxQQBotFileSize {\n    return fmt.Errorf(\"file %d bytes exceeds qqbot limit\", len(fileData))\n}\nif groupOpenID == \"\" {\n    return fmt.Errorf(\"cannot send: empty group openID\")\n}","typeGuard":null,"tryCatchPattern":"var apiErr struct{ Code int `json:\"code\"`; Message string `json:\"message\"` }\nif m := reBody.FindStringSubmatch(err.Error()); m != nil {\n    _ = json.Unmarshal([]byte(m[1]), &apiErr) // parse raw body from the error text\n    switch apiErr.Code {\n    case rateLimitedCode:\n        // backoff and retry\n    default:\n        slog.Error(\"qqbot api error after retry\", \"code\", apiErr.Code, \"msg\", apiErr.Message)\n    }\n}","preventionTips":["Stay under QQ rich media size limits before calling SendImage/SendFile.","Verify the bot is a member of the target group before sending.","Increment msg_seq per msg_id to avoid dedup rejections.","Back off on rate-limit codes surfaced in the response body."],"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"}