chenhg5/cc-connect · error

qqbot: api %s %s returned %d: %s

Error message

qqbot: api %s %s returned %d: %s

What it means

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.

Source

Thrown at platform/qqbot/qqbot.go:370

			return fmt.Errorf("qqbot: api retry failed: %w", err)
		}
		defer resp2.Body.Close()

		if resp2.StatusCode >= 300 {
			raw, _ := io.ReadAll(resp2.Body)
			return fmt.Errorf("qqbot: api %s %s returned %d (after retry): %s", method, url, resp2.StatusCode, raw)
		}
		if result != nil {
			if err := json.NewDecoder(resp2.Body).Decode(result); err != nil {
				return fmt.Errorf("qqbot: decode response: %w", err)
			}
		}
		return nil
	}

	if resp.StatusCode >= 300 {
		raw, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("qqbot: api %s %s returned %d: %s", method, url, resp.StatusCode, raw)
	}
	if result != nil {
		if err := json.NewDecoder(resp.Body).Decode(result); err != nil {
			return fmt.Errorf("qqbot: decode response: %w", err)
		}
	}
	return nil
}

var _ core.ImageSender = (*Platform)(nil)

// buttonDataPrefix is the prefix for QQ Bot keyboard button_data values.
// Format: perm:<decision>:<session_key>
const buttonDataPrefix = "perm:"

// SendFile uploads and sends a file via QQ Bot rich media API.
// Implements core.FileSender.
func (p *Platform) SendFile(ctx context.Context, replyCtx any, file core.FileAttachment) error {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Parse the raw body included in the error — QQ error codes identify the exact problem.
  2. 429: implement/exercise backoff; check msg_seq incrementing via nextMsgSeq.
  3. 404/400 with openID: verify the bot is in the group and the openID is from the same app.
  4. 413 on upload: shrink the file before calling SendImage/SendFile.
  5. Check QQ Open Platform status page for ongoing incidents on 5xx.
  6. Read the raw body in the error message — the QQ API error code explains the cause (e.g. 11253 rate limit, invalid openID).
Defensive patterns

Strategy: try-catch

Validate before calling

if len(data) > maxUploadBytes {
    return fmt.Errorf("attachment too large for qqbot: %d bytes", len(data))
}
if rctx.GroupOpenID == "" && rctx.UserOpenID == "" {
    return fmt.Errorf("no target openID for qqbot send")
}

Try / catch

if err := p.SendImage(ctx, rctx, img); err != nil {
    var status int
    if _, sErr := fmt.Sscanf(err.Error(), "qqbot: api %*s %*s returned %d", &status); sErr == nil && status == 429 {
        time.Sleep(rateLimitBackoff)
        return p.SendImage(ctx, rctx, img) // bounded retry
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/0a2677c03db10ba0. Report an issue: GitHub.