chenhg5/cc-connect · error
weixin: %s: http %d: %s
Error message
weixin: %s: http %d: %s
What it means
post() fails when the iLink API returns any status other than 200. The first 512 bytes of the response body (via truncateForLog) are appended because WeChat usually embeds ret/errcode/errmsg diagnostics in the body. This is the generic HTTP-level failure for all API calls (getUpdates, sendMessage, getUploadUrl, getConfig, sendTyping).
Source
Thrown at platform/weixin/client.go:115
if timeout > 0 {
// Dedicated client so long-poll does not inherit short Timeout from default client.
client = c.longPollClient(timeout)
}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("weixin: %s: %w", label, err)
}
defer resp.Body.Close()
raw, err := io.ReadAll(io.LimitReader(resp.Body, maxIlinkHTTPResponseBody+1))
if err != nil {
return nil, fmt.Errorf("weixin: %s: read body: %w", label, err)
}
if len(raw) > maxIlinkHTTPResponseBody {
return nil, fmt.Errorf("weixin: %s: response body exceeds %d bytes", label, maxIlinkHTTPResponseBody)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("weixin: %s: http %d: %s", label, resp.StatusCode, truncateForLog(raw, 512))
}
return raw, nil
}
func truncateForLog(b []byte, max int) string {
s := string(b)
if len(s) <= max {
return s
}
return s[:max] + "…"
}
func (c *apiClient) getUpdates(ctx context.Context, buf string, timeoutMs int) (*getUpdatesResp, error) {
timeout := defaultLongPollTimeout
if timeoutMs > 0 {
timeout = time.Duration(timeoutMs) * time.Millisecond
}
req := getUpdatesReq{View on GitHub (pinned to 4000b2338a)
Solutions
- Read the status code and the truncated body in the error — it usually contains errcode/errmsg explaining the rejection
- For 401/403, regenerate/refresh the ilink bot token in config.toml and restart
- For 429, add backoff/rate limiting to outbound messages
- For 5xx, retry later — transient WeChat-side failure; check service status
Example fix
// before: treating every non-200 as fatal
if err := client.sendMessage(ctx, msg); err != nil { return err }
// after: branch on the embedded status
if err := client.sendMessage(ctx, msg); err != nil {
var se struct{ code int }
if _, scan := fmt.Sscanf(err.Error(), "weixin: sendMessage: http %d", &se.code); scan == nil && se.code == 429 {
time.Sleep(time.Minute); return client.sendMessage(ctx, msg)
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify the token before starting the engine
if strings.TrimSpace(token) == "" { return fmt.Errorf("weixin: missing bot token") }
// optionally: dry-run an authenticated call at startup Try / catch
if err != nil {
var httpErr struct{ status int }
if n, _ := fmt.Sscanf(err.Error(), "weixin: %*s: http %d", &httpErr.status); n == 1 {
switch {
case httpErr.status == 401 || httpErr.status == 403: // refresh token
case httpErr.status == 429: // backoff
default: // log and retry later
}
}
} Prevention
- Keep the ilink bot token valid and rotate before expiry
- Implement backoff for 429s and circuit-breaking for sustained 5xx
- Validate outgoing message payloads (non-empty item_list, valid to_user_id) to avoid 400s
- Alert on any spike of non-200 responses from the iLink API
When it happens
Trigger: Any ilink/bot/* POST returning 4xx/5xx — invalid or expired bot token (401/403), bad request payload (400), rate limiting (429), or server errors (5xx).
Common situations: Expired or revoked ilink_bot_token in config.toml; malformed send message payload; WeChat API rate limiting under burst; temporary iLink service outage (5xx).
Related errors
- http %d: %s
- api returned status %d: %s
- usage endpoint returned status %d: %s
- reasonix: POST %s returned %d: %s
- gitee API returned HTTP %d
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/5bf45286cc629c06.
Report an issue: GitHub.