chenhg5/cc-connect · error
AI card delivery failed: %s
Error message
AI card delivery failed: %s
What it means
DingTalk returned HTTP 200 but the response's deliverResults array contains an entry with success=false, meaning the card instance was created but could not actually be delivered to the conversation (platform/dingtalk/card.go:198, createAICard). The DingTalk per-delivery errorMsg is embedded in the error. Unlike transport failures, this is an application-level rejection by DingTalk's IM delivery pipeline.
Source
Thrown at platform/dingtalk/card.go:198
}
// Check deliverResults for actual delivery success
var deliverCheck struct {
Result struct {
DeliverResults []struct {
Success bool `json:"success"`
ErrorMsg string `json:"errorMsg"`
} `json:"deliverResults"`
} `json:"result"`
}
if err := json.Unmarshal(respBody, &deliverCheck); err == nil {
for _, dr := range deliverCheck.Result.DeliverResults {
if !dr.Success {
slog.Warn("dingtalk: AI card delivery failed",
"errorMsg", dr.ErrorMsg,
"outTrackId", outTrackId,
"isGroup", isGroup)
return nil, fmt.Errorf("AI card delivery failed: %s", dr.ErrorMsg)
}
}
}
slog.Info("dingtalk: AI card created",
"cardInstanceId", cardInstanceId,
"outTrackId", resolvedOutTrackId)
card := &aiCard{
cardInstanceId: cardInstanceId,
outTrackId: resolvedOutTrackId,
templateKey: p.cardTemplateKey,
platform: p,
state: "processing",
throttleMs: p.cardThrottleMs,
done: make(chan struct{}),
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Read the embedded errorMsg — it names the delivery failure reason
- For groups: re-add the robot to the target group chat and confirm the robot's app scope includes that org/users
- For 1:1 chats: confirm the user hasn't blocked the robot and is inside the app's visible range
- Verify conversationId/senderStaffId come from the current incoming message, not a stale cached session
- Check robotCode in config matches the robot actually delivering messages in that conversation
Defensive patterns
Strategy: fallback
Validate before calling
// ensure robot can deliver before starting a card flow
// robot must be a member of the group and within app visibility scope
if rc.isGroup && !robotInGroup(rc.conversationId, p.robotCode) {
return fmt.Errorf("robot %s not in group %s; delivery will fail", p.robotCode, rc.conversationId)
} Try / catch
card, err := p.CreateStreamingCard(ctx, msg)
if err != nil && strings.Contains(err.Error(), "AI card delivery failed:") {
// DingTalk rejected delivery: fall back to plain text reply
p.Reply(ctx, msg, content)
} Prevention
- Add the robot to every group it should serve; verify app visibility covers all target users
- Use conversationId/senderStaffId only from the live incoming message, never cached stale sessions
- Confirm robotCode in config equals the robot actually installed in the conversation
- Periodically re-check group membership after group reorganizations
When it happens
Trigger: The createAndDeliver response contains result.deliverResults[i] with success=false and a non-empty errorMsg, e.g. when the robot is not a member of the target group, the target user has blocked the robot, or the openSpaceId (derived from conversationId/senderStaffId) doesn't match a live conversation.
Common situations: Robot removed from or never added to the group chat; 1:1 chat where the user blocked/disabled the robot; stale conversationId from a session after the chat was disbanded; robotCode mismatch with the robot actually in the conversation; user not visible to the app's visibility scope.
Related errors
- create AI card: status=%d, body=%s
- stream AI card: status=%d, body=%s
- get access token: %w
- get download URL: %w
- get access token: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/206c3f54bf60e973.
Report an issue: GitHub.