chenhg5/cc-connect · error
qqbot: decode response: %w
Error message
qqbot: decode response: %w
What it means
On the 401-retry path, when the retried response status is 2xx but the JSON body cannot be decoded into the caller's result struct, this wrapped error is returned. It indicates the QQ API returned a successful status with an unexpected or malformed payload — e.g. an HTML error page behind a proxy or an undocumented response shape.
Source
Thrown at platform/qqbot/qqbot.go:362
if err != nil {
return fmt.Errorf("qqbot: build retry request: %w", err)
}
req2.Header.Set("Authorization", "QQBot "+token)
req2.Header.Set("Content-Type", "application/json")
resp2, err := core.HTTPClient.Do(req2)
if err != nil {
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)View on GitHub (pinned to 4000b2338a)
Solutions
- Log the raw response body at the failure point to see what was actually returned.
- Check for a proxy/gateway rewriting responses (HTML in body = middlebox issue).
- Verify the result struct's JSON tags against the current QQ Bot API docs.
- Update to the latest cc-connect version in case the API schema changed.
- If the body is empty, check whether the endpoint now returns 204 with no body.
Example fix
// before
var result struct{ FileInfo string `json:"file_info"` }
// after (tolerate alternate field naming confirmed from API docs)
var result struct{ FileInfo string `json:"file_info"` }
// (fix usually means updating the struct tag or handling a 204/no-body response, not the caller) Defensive patterns
Strategy: type-guard
Validate before calling
// Sanity-check the raw body before decoding in a wrapper:
raw, _ := io.ReadAll(resp.Body)
if !json.Valid(raw) || len(raw) == 0 {
return fmt.Errorf("qqbot: non-JSON or empty response from proxy/api")
} Try / catch
if err := send(); err != nil {
if strings.Contains(err.Error(), "decode response") {
slog.Warn("qqbot returned unexpected 2xx body; check proxy/interference", "err", err)
}
} Prevention
- Ensure no proxy/gateway rewrites HTTPS responses (HTML with 200).
- Keep cc-connect updated against QQ API schema changes.
- Log raw bodies on decode failure to diagnose quickly.
- Verify expected endpoints actually return bodies (some may legitimately be empty).
When it happens
Trigger: resp2 is 2xx and json.Decoder.Decode(result) fails: truncated body, non-JSON content (proxy/gateway interference), or a field in the result struct whose type does not match the actual JSON (e.g. string vs number).
Common situations: Corporate proxy or captive portal returning HTML with 200; QQ API schema change; uploadRichMedia's {file_info} struct receiving a different shape; gzip/encoding issues from a misconfigured middlebox.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- gateway response decode: %w
- decode usage response: %w
- parse JSON from %s: %w
- decode: %w
- parse JSON from %s: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/3a126e459645f025.
Report an issue: GitHub.