fix(reactions): accept emoji with variation selectors / ZWJ / skin tones (❤️ silently failed)#744
Merged
Merged
Conversation
SAFE_EMOJI_RE was /^[\p{Emoji}]{1,8}$/u. `\p{Emoji}` does NOT match the
combining marks real emoji carry — U+FE0F (variation selector), skin-tone
modifiers — so ❤️ (U+2764 U+FE0F), which is in the client's reaction palette,
400'd with "emoji must be 1–8 emoji characters". The frontend swallows reaction
errors, so clicking ❤️ did nothing: users perceived "reactions can't show more
than one" (their obvious second reaction, love, silently failed). Confirmed live
against the API on 2026-07-24; the backend count aggregation and the UI count
render were both verified correct — this validation was the whole bug.
Fix: widen the char class to allow U+FE0F, U+200D (ZWJ sequences), and
\p{Emoji_Modifier} (skin tones); raise the cap to 16 code points for sequences.
Test: reactionController.emojiValidation.test.js — ❤️, 👍🏽, 👨👩👧 accepted;
plain non-emoji still 400s.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DMeWzgFxsfBcjoLVLewEES
The reaction toggle caught and ignored all errors, so a rejected reaction (bad-emoji 400, non-member 403, rate-limit 429) did nothing visible. That silence is what made the ❤️-validation bug read as "reactions can't show more than one" — the second reaction just vanished. Now show the server message (or a status-mapped fallback) for ~4s beneath the chips. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DMeWzgFxsfBcjoLVLewEES
This was referenced Jul 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug (2026-07-24, reported during launch)
"Reactions can't show more than one." Root cause:
SAFE_EMOJI_RErejected❤️.const SAFE_EMOJI_RE = /^[\p{Emoji}]{1,8}$/u—\p{Emoji}matches base emoji code points but not the combining marks real emoji carry:U+FE0F(variation selector),U+200D(ZWJ), skin-tone modifiers.❤️isU+2764+U+FE0F, so it failed with 400 "emoji must be 1–8 emoji characters."❤️is in the client's reaction palette (['👍','❤️','🔥','🤔','👀','🚀']), and the frontend swallows reaction errors — so clicking ❤️ did nothing. Users reacted 👍 (a plain single code point, worked), tried ❤️ (silently failed) → "can't add a second reaction."Verified live:
curlPOST❤️→ 400; the backend count aggregation (listForMessage→count:2for two users) and the UI count render (Playwright showed👍 ×2) were both confirmed correct. This validation was the entire bug.Fix
Allows variation selectors, ZWJ sequences, and skin-tone modifiers; cap raised to 16 code points for family/profession sequences.
Test
reactionController.emojiValidation.test.js—❤️,👍🏽,👨👩👧accepted; non-emoji still 400s. Existing reactionController suite green.Related (separate, not in this PR)
V2MessageBubbletoggle catch) — surfacing them would have made this obvious. Worth a small follow-up.publicReadpods.🤖 Generated with Claude Code
https://claude.ai/code/session_01DMeWzgFxsfBcjoLVLewEES