{"record":{"id":"1e96f4d6277b2ec6","repo":"RocketChat/Rocket.Chat","slug":"the-required-id-query-param-is-missing","errorCode":null,"errorMessage":"The required \"_id\" query param is missing.","messagePattern":"The required \"_id\" query param is missing\\.","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/emoji-custom.ts","lineNumber":247,"sourceCode":"\t\t\t\t\trequired: ['success'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t}),\n\t\t\t\t400: validateBadRequestErrorResponse,\n\t\t\t\t401: validateUnauthorizedErrorResponse,\n\t\t\t},\n\t\t},\n\t\tasync function action() {\n\t\t\tconst emoji = await getUploadFormData(\n\t\t\t\t{\n\t\t\t\t\trequest: this.request,\n\t\t\t\t},\n\t\t\t\t{ field: 'emoji', sizeLimit: settings.get('FileUpload_MaxFileSize'), fileOptional: true },\n\t\t\t);\n\n\t\t\tconst { fields, fileBuffer, mimetype } = emoji;\n\n\t\t\tif (!fields._id) {\n\t\t\t\tthrow new Meteor.Error('The required \"_id\" query param is missing.');\n\t\t\t}\n\n\t\t\tconst emojiToUpdate = await EmojiCustom.findOneById<Pick<IEmojiCustom, 'name' | 'extension'>>(fields._id, {\n\t\t\t\tprojection: { name: 1, extension: 1 },\n\t\t\t});\n\t\t\tif (!emojiToUpdate) {\n\t\t\t\tthrow new Meteor.Error('Emoji not found.');\n\t\t\t}\n\n\t\t\tconst emojiData: EmojiData = {\n\t\t\t\tpreviousName: emojiToUpdate.name,\n\t\t\t\tpreviousExtension: emojiToUpdate.extension,\n\t\t\t\taliases: fields.aliases || '',\n\t\t\t\tname: fields.name,\n\t\t\t\textension: fields.extension,\n\t\t\t\t_id: fields._id,\n\t\t\t\tnewFile: false,\n\t\t\t};","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/emoji-custom.ts#L229-L265","documentation":"Thrown by POST emoji-custom.update when the multipart form field '_id' is missing/falsy. DEFECT: it is built as new Meteor.Error('The required \"_id\" query param is missing.') — the human message occupies the error-CODE slot, so there is no structured code and clients cannot match on a stable key. Also note it says 'query param' but _id is actually a form field.","triggerScenarios":"Update call without the _id field in the multipart body; field name typo (e.g. 'id' instead of '_id'); form serialization drops falsy ids.","commonSituations":"Client form omits the selected emoji's id; refactor changed the field name; building FormData from an object without _id.","solutions":["Always include the existing emoji's _id in the emoji form data when updating.","Client-side assert _id is present before opening the upload.","When matching errors, key on the message substring rather than expecting a normal code."],"exampleFix":"// before\nconst fd = new FormData(); fd.append('name', newName); // forgot _id\n// after\nif (!emojiId) throw new Error('no emoji selected to update');\nconst fd = new FormData(); fd.append('_id', emojiId); fd.append('name', newName);","handlingStrategy":"validation","validationCode":"if (!emojiId) throw new Error('select an emoji to update');\nconst fd = new FormData(); fd.append('_id', emojiId);","typeGuard":"function hasId(fields): fields is { _id: string } { return typeof fields?._id === 'string' && fields._id.length > 0; }","tryCatchPattern":"try { await updateEmojiCustom(fd); }\ncatch (e) {\n  // note: the message IS the code here (no structured code)\n  if (/\"_id\" query param is missing/i.test(e?.error || '')) { /* add _id field */) }\n  else throw e;\n}","preventionTips":["Always append _id to the update FormData.","Require an emoji selection before opening the editor.","Match on the message substring, not a structured code, due to the construction defect."],"tags":["emoji-custom","validation","bug","rest-api"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}