sipeed/picoclaw · warning
feishu react: %w
Error message
feishu react: %w
What it means
FeishuChannel's React path called lark SDK Im.V1.MessageReaction.Create and the SDK returned a transport-level error before parsing a business response. The function returns a no-op undo func plus this wrapped error, and logs the emoji, message_id, and cause. Reactions are auxiliary UX; failing to add one should not fail the send pipeline.
Source
Thrown at pkg/channels/feishu/feishu_64.go:452
if len(candidates) > 0 {
chosenEmoji = candidates[rand.Intn(len(candidates))]
}
req := larkim.NewCreateMessageReactionReqBuilder().
MessageId(messageID).
Body(larkim.NewCreateMessageReactionReqBodyBuilder().
ReactionType(larkim.NewEmojiBuilder().EmojiType(chosenEmoji).Build()).
Build()).
Build()
resp, err := c.client.Im.V1.MessageReaction.Create(ctx, req)
if err != nil {
logger.ErrorCF("feishu", "Failed to add reaction", map[string]any{
"emoji": chosenEmoji,
"message_id": messageID,
"error": err.Error(),
})
return func() {}, fmt.Errorf("feishu react: %w", err)
}
if !resp.Success() {
c.invalidateTokenOnAuthError(resp.Code)
logger.ErrorCF("feishu", "Reaction API error", map[string]any{
"emoji": chosenEmoji,
"message_id": messageID,
"code": resp.Code,
"msg": resp.Msg,
})
return func() {}, fmt.Errorf("feishu react api error (code=%d msg=%s)", resp.Code, resp.Msg)
}
var reactionID string
if resp.Data != nil && resp.Data.ReactionId != nil {
reactionID = *resp.Data.ReactionId
}
if reactionID == "" {
return func() {}, nilView on GitHub (pinned to 49183d7e8d)
Solutions
- Retry once or twice with a short delay - transport errors are transient
- If it persists, verify connectivity to open.feishu.cn
- Downgrade the failure to a warning: the message itself was sent successfully
Example fix
// before
undo, err := ch.React(ctx, chatID, msgID, emoji)
if err != nil {
return err // emoji failure kills a successful send
}
// after
undo, err := ch.React(ctx, chatID, msgID, emoji)
if err != nil {
logger.Warn("reaction failed (non-fatal)", "err", err)
undo = func() {}
} Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
func isReactTransportError(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "feishu react: ") && !strings.Contains(err.Error(), "feishu react api error")
} Try / catch
undo, err := ch.React(ctx, chatID, msgID, emoji)
for i := 0; isReactTransportError(err) && i < 2; i++ {
time.Sleep(300 * time.Millisecond)
undo, err = ch.React(ctx, chatID, msgID, emoji)
}
if err != nil {
logger.Warn("reaction failed (cosmetic)", "err", err)
undo = func() {}
} Prevention
- Retry reactions briefly but never propagate their failure to the send flow
- The returned undo func is a no-op on failure - safe to call unconditionally
- Batch reactions away from the critical send moment to dodge bursts
- Watch logged emoji/message_id pairs to spot systematic offenders
When it happens
Trigger: POST reaction API fails at the network layer: timeout, connection reset, DNS failure while attaching an emoji reaction to a message.
Common situations: Transient network blips right after a successful send; proxies rate-limiting a burst of send+react calls; slow mobile uplinks.
Related errors
- feishu edit: %w
- feishu delete: %w
- feishu react api error (code=%d msg=%s)
- feishu edit api error (code=%d msg=%s)
- feishu delete api error (code=%d msg=%s)
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/d59ceba91370a848.
Report an issue: GitHub.