{"record":{"id":"4524b001b3261d7d","repo":"hcengineering/platform","slug":"modifications-of-reaction-type-are-not-allowed","errorCode":null,"errorMessage":"Modifications of reaction type are not allowed.","messagePattern":"Modifications of reaction type are not allowed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server-plugins/rating/src/index.ts","lineNumber":98,"sourceCode":"    const current = await this.provideFindAll(ctx, rating.class.DocReaction, {\n      attachedTo: create.attachedTo,\n      attachedToClass: create.objectClass\n    })\n    if (\n      current.some(\n        (it) =>\n          it.reactionType === create.attributes.reactionType &&\n          (it.value === create.attributes.value ||\n            (create.attributes.reactionType === ReactionKind.Emoji && it.emoji === create.attributes.emoji))\n      )\n    ) {\n      throw new Error('Duplicate emoji reaction is not allowed.')\n    }\n  }\n\n  private async validateReactionUpdate (ctx: MeasureContext, upd: TxUpdateDoc<DocReaction>): Promise<void> {\n    if (upd.operations.reactionType !== undefined) {\n      throw new Error('Modifications of reaction type are not allowed.')\n    }\n    // Find current reaction tried to be modified\n    const current = (\n      await this.provideFindAll(ctx, rating.class.DocReaction, {\n        _id: upd.objectId,\n        _class: upd.objectClass\n      })\n    ).shift()\n    if (current === undefined) {\n      throw new Error('Reaction not found.')\n    }\n    if (upd.operations.value === undefined || upd.operations.value < 0 || upd.operations.value > 10) {\n      throw new Error('Reaction value modification is required.')\n    }\n  }\n\n  private async validateReactionRemove (ctx: MeasureContext, upd: TxRemoveDoc<DocReaction>): Promise<void> {\n    // Find current reaction tried to be modified","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server-plugins/rating/src/index.ts#L80-L116","documentation":"validateReactionUpdate inspects TxUpdateDoc for DocReaction and rejects any operation attempting to change the reactionType field, since reactions are immutable in kind after creation (change = remove + create a new reaction). Only other permitted fields may be updated.","triggerScenarios":"Submitting an update transaction on a DocReaction whose operations include reactionType — e.g. UI letting a user switch a Like to an Emoji in place, or migration code patching reactionType on existing rows.","commonSituations":"Frontend reaction picker updating the same doc instead of deleting and re-creating, bulk scripts normalizing reaction types, schema migrations adjusting reactionType values.","solutions":["To change a reaction type, delete the existing DocReaction and create a new one with the desired type.","Update the client to replace update-with-reactionType by remove+create flow.","Remove reactionType from any migration/bulk update operation sets on DocReaction."],"exampleFix":"// before\nawait client.updateDoc(rating.class.DocReaction, _id, { reactionType: ReactionKind.Emoji })\n// after\nawait client.removeDoc(rating.class.DocReaction, space, _id)\nawait client.createDoc(rating.class.DocReaction, space, {\n  attachedTo: docId,\n  reactionType: ReactionKind.Emoji,\n  emoji: '👍'\n})","handlingStrategy":"validation","validationCode":"const ops: Record<string, any> = { ...update.operations }\nif ('reactionType' in ops) {\n  throw new Error('Remove and re-create the reaction to change its type')\n}","typeGuard":"function isReactionTypeUpdate(upd: TxUpdateDoc<DocReaction>): boolean {\n  return upd.operations.reactionType !== undefined\n}","tryCatchPattern":"try {\n  await client.updateDoc(rating.class.DocReaction, _id, ops)\n} catch (err) {\n  if (/Modifications of reaction type/.test(err.message)) {\n    await client.removeDoc(rating.class.DocReaction, space, _id)\n    await client.createDoc(rating.class.DocReaction, space, newReaction)\n    return\n  }\n  throw err\n}","preventionTips":["Model reaction-type changes as remove+create in the client.","Strip reactionType from any update operation sets.","Document DocReaction immutability rules for UI developers.","Add tests rejecting updates touching reactionType."],"tags":["rating","reactions","immutability","validation"],"backgroundTag":"immutable-reaction-field","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}