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.
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.
- account.status.BadRequest
- account.status.BadRequest
- Accounts url not specified
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/0595af80174fb338.
Report an issue: GitHub.
Appendix: 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)