RocketChat/Rocket.Chat · error · Meteor.Error
The required "_id" query param is missing.
Error message
The required "_id" query param is missing.
What it means
Thrown by POST emoji-custom.update when the multipart form data contains no _id field. The endpoint reads everything through getUploadFormData and expects the emoji's document id as a form field named _id; unlike most REST endpoints it is not taken from the URL query or a JSON body. Note the error is constructed with a single argument, so the message doubles as the error identifier in the response.
Solutions
- Add a plain text multipart form field named exactly _id carrying the emoji document id: form.append('_id', emojiId)
- Get the correct id first from GET emoji-custom.list / emoji-custom.all (the _id property of each emoji)
- Keep sending the rest of the payload as multipart/form-data with the optional 'emoji' file field - do not switch the request to application/json
Example fix
// before
const form = new FormData();
form.append('name', 'new-name');
form.append('emoji', file); // _id never sent
// after
const form = new FormData();
form.append('_id', emojiId);
form.append('name', 'new-name');
form.append('emoji', file); Defensive patterns
Strategy: validation
Validate before calling
function buildEmojiUpdateForm(emojiId, fields, file) {
if (!emojiId) throw new Error('emoji-custom.update requires the emoji _id');
const form = new FormData();
form.append('_id', emojiId);
for (const [k, v] of Object.entries(fields)) form.append(k, v);
if (file) form.append('emoji', file);
return form;
} Type guard
const hasEmojiId = (body: Record<string, unknown>): body is { _id: string } & Record<string, unknown> =>
typeof body._id === 'string' && body._id.length > 0; Try / catch
try { await sdk.post('emoji-custom.update', form); } catch (e) {
if (String(e.message).includes('"_id" query param is missing')) { /* attach _id field and retry once */ }
} Prevention
- Remember emoji-custom.update is multipart/form-data; _id is a form field, not a URL/JSON param
- Write one form-builder function so every call site gets _id handling right
- Fetch the _id from emoji-custom.list immediately before updating to avoid stale ids
When it happens
Trigger: POST /api/v1/emoji-custom.update with multipart fields name/aliases/emoji but no _id field; sending _id as a query parameter (?_id=abc) or inside a JSON body - the handler never sees it because it only reads getUploadFormData fields; a typo like 'id' or 'emojiId' instead of '_id'.
Common situations: Developers assuming REST conventions where the id goes in the URL or query string; clients switching from emoji-custom.delete (which uses emojiId in a JSON body) to update and reusing the field name; multipart builders that drop fields with underscore-prefixed names.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- emoji-is-not-image
- Emoji not found.
- error-room-param-not-provided
- error-roomId-param-invalid
- agent-not-found
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/1e96f4d6277b2ec6.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/server/api/v1/emoji-custom.ts:247
required: ['success'],
additionalProperties: false,
}),
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const emoji = await getUploadFormData(
{
request: this.request,
},
{ field: 'emoji', sizeLimit: settings.get('FileUpload_MaxFileSize'), fileOptional: true },
);
const { fields, fileBuffer, mimetype } = emoji;
if (!fields._id) {
throw new Meteor.Error('The required "_id" query param is missing.');
}
const emojiToUpdate = await EmojiCustom.findOneById<Pick<IEmojiCustom, 'name' | 'extension'>>(fields._id, {
projection: { name: 1, extension: 1 },
});
if (!emojiToUpdate) {
throw new Meteor.Error('Emoji not found.');
}
const emojiData: EmojiData = {
previousName: emojiToUpdate.name,
previousExtension: emojiToUpdate.extension,
aliases: fields.aliases || '',
name: fields.name,
extension: fields.extension,
_id: fields._id,
newFile: false,
};View on GitHub (pinned to b2c16d5842)