hcengineering/platform · warning
Duplicate emoji reaction is not allowed.
Error message
Duplicate emoji reaction is not allowed.
What it means
When a DocReaction creation transaction arrives, the plugin validates that the user has not already created an identical reaction: same reactionType and same value, or for Emoji reactions the same emoji. If an equivalent existing reaction is found, the duplicate create is rejected with this error.
Source
Thrown at server-plugins/rating/src/index.ts:92
}
return await this.provideTx(ctx, tx)
}
private async validateNewReaction (ctx: MeasureContext, create: TxCreateDoc<DocReaction>): Promise<void> {
// Should allow only one reaction per document per user for Emoji, Like, Usefull
const current = await this.provideFindAll(ctx, rating.class.DocReaction, {
attachedTo: create.attachedTo,
attachedToClass: create.objectClass
})
if (
current.some(
(it) =>
it.reactionType === create.attributes.reactionType &&
(it.value === create.attributes.value ||
(create.attributes.reactionType === ReactionKind.Emoji && it.emoji === create.attributes.emoji))
)
) {
throw new Error('Duplicate emoji reaction is not allowed.')
}
}
private async validateReactionUpdate (ctx: MeasureContext, upd: TxUpdateDoc<DocReaction>): Promise<void> {
if (upd.operations.reactionType !== undefined) {
throw new Error('Modifications of reaction type are not allowed.')
}
// Find current reaction tried to be modified
const current = (
await this.provideFindAll(ctx, rating.class.DocReaction, {
_id: upd.objectId,
_class: upd.objectClass
})
).shift()
if (current === undefined) {
throw new Error('Reaction not found.')
}
if (upd.operations.value === undefined || upd.operations.value < 0 || upd.operations.value > 10) {View on GitHub (pinned to 63e28dc964)
Solutions
- Catch this error client-side and treat it as success/idempotent (the reaction already exists).
- Query existing DocReaction for (user, attachedTo, reactionType) before creating.
- Debounce/disable the reaction button until the server confirms.
- Make the create idempotent by checking via findAll on the plugin before submitting the tx.
Example fix
// before
await client.createDoc(rating.class.DocReaction, space, reaction)
// after
const existing = await client.findAll(rating.class.DocReaction, {
attachedTo: docId, createdBy: me, reactionType: reaction.reactionType
})
if (existing.length === 0) {
await client.createDoc(rating.class.DocReaction, space, reaction)
} Defensive patterns
Strategy: try-catch
Validate before calling
const existing = await client.findAll(rating.class.DocReaction, {
attachedTo: docId,
createdBy: myAccountId,
reactionType,
})
if (existing.length > 0) return // already reacted; skip create Try / catch
try {
await client.createDoc(rating.class.DocReaction, space, reaction)
} catch (err) {
if (/Duplicate emoji reaction/.test(err.message)) {
return // idempotent: reaction already recorded
}
throw err
} Prevention
- Debounce like/emoji buttons until server confirmation.
- Check for an existing identical reaction before creating.
- Treat duplicate errors as success for idempotent UX.
- Guard against offline sync replaying reaction creates.
When it happens
Trigger: Submitting TxCreateDoc for rating.class.DocReaction when the same user already has a reaction on the same attachedTo doc with the same reactionType and value/emoji — e.g. double-clicking a like button, retrying a request that actually succeeded, or replayed transactions.
Common situations: UI not debouncing star/like clicks, optimistic-UI retries after network timeouts, offline clients syncing queued reactions twice, event/tx replays.
Related errors
- Modifications of reaction type are not allowed.
- Direct modifications of ratings are not allowed.
- Failed to load server config
- getDisplayMedia not supported
- No screen access granted
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/0595af80174fb338.
Report an issue: GitHub.