chenhg5/cc-connect · error
dingtalk: proactive send failed: status=%d, body=%s
Error message
dingtalk: proactive send failed: status=%d, body=%s
What it means
The DingTalk proactive-send API responded with a non-200 HTTP status. The error includes the numeric status and the raw response body so the DingTalk-side failure reason (invalid token, invalid robot code, bad conversationId, rate limit) can be diagnosed. This is a server-rejected request, not a transport failure.
Source
Thrown at platform/dingtalk/dingtalk.go:1698
return fmt.Errorf("dingtalk: marshal proactive message: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(body))
if err != nil {
return fmt.Errorf("dingtalk: create proactive request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-acs-dingtalk-access-token", token)
resp, err := p.httpClient.Do(req)
if err != nil {
return fmt.Errorf("dingtalk: proactive send request: %w", err)
}
defer func() { _ = resp.Body.Close() }()
respBody, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("dingtalk: proactive send failed: status=%d, body=%s", resp.StatusCode, string(respBody))
}
slog.Debug("dingtalk: proactive message sent", "api", apiURL, "status", resp.StatusCode)
return nil
}
var atUserIDRegexp = regexp.MustCompile(`@(\d{4,})`)
// extractAtUserIds extracts @userId patterns from content for DingTalk's atUserIds field.
// Matches @ followed by numeric DingTalk user IDs (e.g. @194252073827812352).
func extractAtUserIds(content string) []string {
matches := atUserIDRegexp.FindAllStringSubmatch(content, -1)
seen := make(map[string]bool)
var ids []string
for _, m := range matches {
if len(m) > 1 && !seen[m[1]] {
seen[m[1]] = true
ids = append(ids, m[1])View on GitHub (pinned to 4000b2338a)
Solutions
- Read the status and body in the error message; DingTalk bodies contain errcode/errmsg pinpointing the cause.
- If status is 401/invalid token: refresh the access token (it expires ~2h) and retry; verify appKey/appSecret used to get the token.
- Verify robotCode matches the app's robot, and that the bot is a member of the target group for group sends.
- Check the conversationId/staffId values are current; re-capture them from a live inbound message.
- If status is 429 or body mentions limit, slow down and add backoff retry.
Example fix
// before
token := p.tokenCache.Get() // may be hours old
p.sendProactive(ctx, token, requestBody)
// after
token, err := p.getAccessToken(ctx) // refreshes when near expiry
if err != nil {
return fmt.Errorf("dingtalk: refresh token: %w", err)
}
p.sendProactive(ctx, token, requestBody) Defensive patterns
Strategy: try-catch
Try / catch
err := p.Send(ctx, rc, msg)
if err != nil {
var apiErr struct{ Status int; Body string }
if strings.Contains(err.Error(), "proactive send failed: status=") {
slog.Error("dingtalk rejected proactive send", "err", err) // body has errcode/errmsg
if strings.Contains(err.Error(), "invalidAuthentication") {
// refresh token and retry once
}
}
} Prevention
- Refresh the access token proactively before its ~2h expiry
- Verify the bot is a member of the target group for group sends
- Validate robotCode, conversationId, and staffId against a live inbound message
- Handle 429 with backoff and reduce send rate
When it happens
Trigger: The POST to the DingTalk proactive-send endpoint completed but resp.StatusCode != 200 — e.g. expired/invalid access token (invalidAuthentication), wrong robotCode, unknown conversationId/staffId, or exceeded QPS limits.
Common situations: Access token cached past its 2-hour expiry; robot not added to the target group so the conversationId is unauthorized; typo'd staffId; hitting DingTalk API rate limits during bulk notifications.
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
- code=%d msg=%s
- get access token: %w
- dingtalk: get access token for emotion: %w
- dingtalk: get access token: %w
- dingtalk: send file failed: status=%d, body=%s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/737d9ab793bc0903.
Report an issue: GitHub.