chenhg5/cc-connect · error
create AI card: status=%d, body=%s
Error message
create AI card: status=%d, body=%s
What it means
DingTalk's createAndDeliver endpoint returned a non-200 HTTP status when creating the AI streaming card (platform/dingtalk/card.go:149, createAICard). The error message embeds the status code and raw response body for diagnosis. Statuses 403, 429, and 5xx additionally trigger activateCardDegrade, which switches the platform to plain-text fallback messages.
Source
Thrown at platform/dingtalk/card.go:149
return nil, fmt.Errorf("do request: %w", err)
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
slog.Debug("dingtalk: createAndDeliver response",
"status", resp.StatusCode,
"body", string(respBody))
if resp.StatusCode != http.StatusOK {
slog.Error("dingtalk: create AI card failed",
"status", resp.StatusCode,
"body", string(respBody))
// Check if we should trigger degrade
if resp.StatusCode == 403 || resp.StatusCode == 429 || resp.StatusCode >= 500 {
p.activateCardDegrade(fmt.Sprintf("card.create:%d", resp.StatusCode))
}
return nil, fmt.Errorf("create AI card: status=%d, body=%s", resp.StatusCode, string(respBody))
}
// Parse response to get cardInstanceId
var result struct {
Result struct {
CardInstanceId string `json:"cardInstanceId"`
OutTrackId string `json:"outTrackId"`
ProcessQueryKey string `json:"processQueryKey"`
} `json:"result"`
CardInstanceId string `json:"cardInstanceId"`
OutTrackId string `json:"outTrackId"`
}
if err := json.Unmarshal(respBody, &result); err != nil {
slog.Warn("dingtalk: failed to parse createAndDeliver response", "error", err, "body", string(respBody))
}
cardInstanceId := result.Result.CardInstanceId
if cardInstanceId == "" {View on GitHub (pinned to 4000b2338a)
Solutions
- Read the embedded body in the error — DingTalk includes a JSON code/message (e.g. INVALID_ACCESS_TOKEN, Forbidden.AccessDenied) naming the cause
- On 401: fix the app's Client Key/Secret in config or the token fetch flow; on 403: grant the robot the card template permission in the DingTalk open platform console
- On 400/404: verify cardTemplateID is a valid template ID published under the same app as the robotCode
- On 429: back off — the platform already activates degrade; reduce streaming update frequency via cardThrottleMs
- On 5xx: retry later; check DingTalk status/announcements
- Confirm robotCode matches the robot bound to the target conversation
Defensive patterns
Strategy: fallback
Validate before calling
// verify token and template before creating cards
tok, err := p.getAccessToken(context.Background())
if err != nil || tok == "" {
log.Printf("dingtalk auth/config problem, expect card creation to fail")
}
if p.cardTemplateID == "" {
log.Printf("cardTemplateID not configured; card creation will 400")
} Try / catch
card, err := p.CreateStreamingCard(ctx, msg)
if err != nil {
var httpErr *HTTPStatusError // or parse status= from err
if m := statusRe.FindStringSubmatch(err.Error()); m != nil && (m[1] == "429" || m[1] >= "500") {
// platform already degraded; fall back to plain text replies
} else if strings.Contains(m[1], "401") || strings.Contains(err.Error(), "403") {
// fix credentials/permissions before retry
}
} Prevention
- Publish the card template under the same DingTalk app as the robot and copy the exact template ID into config
- Grant the robot card/AI-card permissions in the open platform console
- Rotate appSecret promptly after change and restart the daemon
- Respect QPS: keep cardThrottleMs >= 1000 for chatty streams
- Subscribe to DingTalk status announcements for 5xx windows
When it happens
Trigger: POST /v1.0/card/instances/createAndDeliver returns 400/401/403/404/429/5xx: invalid or expired access token (401), robot/template permission denied (403), unknown or inaccessible cardTemplateID (400/404), rate limiting (429), or DingTalk server-side errors (5xx).
Common situations: Wrong or insufficiently scoped cardTemplateID in config.toml; robot lacks the AI-card/template permission in DingTalk admin console; expired access token credentials (Client Key/Secret); exceeding DingTalk API QPS limits; DingTalk service incident.
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
- stream AI card: status=%d, body=%s
- AI card delivery failed: %s
- create request: %w
- do request: %w
- api returned status %d
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/d13517f825441bcd.
Report an issue: GitHub.