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

  1. Read the code/msg in the error: unsupported emoji means your emoji map needs the Feishu emoji_type key, not a unicode character
  2. Permission codes: grant im:message.reaction:create or re-add the bot to the chat
  3. Skip reactions on this message instead of failing - they are cosmetic
  4. 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

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


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/18ff50a3e9957f17. Report an issue: GitHub.