sipeed/picoclaw · warning
feishu react api error (code=%d msg=%s)
Error message
feishu react api error (code=%d msg=%s)
What it means
The reaction-create call parsed but resp.Success() is false: Feishu returned a non-zero business code. Typical causes: the emoji_type is not in Feishu's allowed set, the bot lacks reaction permission in that chat, the message_id is invalid, or the auth token expired (invalidateTokenOnAuthError already ran for auth codes). The code and msg are in the error text and logged.
Source
Thrown at pkg/channels/feishu/feishu_64.go:462
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() {}, nil
}
var undone atomic.Bool
undo := func() {
if !undone.CompareAndSwap(false, true) {
return
}
delReq := larkim.NewDeleteMessageReactionReqBuilder().
MessageId(messageID).
ReactionId(reactionID).View on GitHub (pinned to 49183d7e8d)
Solutions
- Read the code/msg in the error: unsupported emoji means your emoji map needs the Feishu emoji_type key, not a unicode character
- Permission codes: grant im:message.reaction:create or re-add the bot to the chat
- Skip reactions on this message instead of failing - they are cosmetic
- Pin the reaction map to Feishu's documented emoji list and unit-test it
Example fix
// before
emoji := "👍" // unicode: Feishu rejects it
undo, err := ch.React(ctx, chatID, msgID, emoji)
// after
emoji := "THUMBSUP" // Feishu emoji_type key
undo, err := ch.React(ctx, chatID, msgID, emoji)
if err != nil {
logger.Warn("reaction skipped", "emoji", emoji, "err", err)
undo = func() {}
} Defensive patterns
Strategy: fallback
Validate before calling
// validate emoji against Feishu's documented emoji_type keys before calling
var allowedEmojis = map[string]bool{"THUMBSUP": true, "DONE": true, "OK": true /* ... */}
func emojiAllowed(e string) bool { return allowedEmojis[e] } Type guard
func isReactAPIError(err error) bool {
return err != nil && strings.Contains(err.Error(), "feishu react api error")
} Try / catch
undo, err := ch.React(ctx, chatID, msgID, emoji)
if isReactAPIError(err) {
logger.Warn("reaction rejected by API; skipping", "emoji", emoji, "err", err)
undo = func(){}
err = nil // cosmetic feature: never fail the send on it
}
return undo, err Prevention
- Use only Feishu emoji_type keys (THUMBSUP, DONE...), never unicode emoji
- Maintain the allow-list as data and unit-test it against the card builder
- Skip reactions on messages older than a threshold (they may be deleted)
- Log code+msg on reject; unsupported-emoji is by far the most common cause
When it happens
Trigger: MessageReaction.Create with an unsupported emoji_type string, a reaction attempted in a chat the bot cannot react in, or reacting to a deleted message.
Common situations: Custom emoji mappings bypassing the allow-list (Feishu expects types like 'THUMBSUP', 'DONE'); permission scopes trimmed after setup; racing a message deletion.
Related errors
- feishu react: %w
- feishu edit api error (code=%d msg=%s)
- feishu delete api error (code=%d msg=%s)
- feishu placeholder: card build failed: %w
- bot info api error (code=%d)
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/18ff50a3e9957f17.
Report an issue: GitHub.