{"record":{"id":"766267498db208fb","repo":"RocketChat/Rocket.Chat","slug":"error-roomid-param-invalid","errorCode":"error-roomId-param-invalid","errorMessage":"The \"${paramName}\" query parameter must be a valid date.","messagePattern":"The \"(.+?)\" query parameter must be a valid date\\.","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/emoji-custom.ts","lineNumber":59,"sourceCode":"});\n\nconst emojiCustomDeleteResponseSchema = ajv.compile<void>({\n\ttype: 'object',\n\tproperties: {\n\t\tsuccess: { type: 'boolean', enum: [true] },\n\t},\n\trequired: ['success'],\n\tadditionalProperties: false,\n});\n\nfunction validateDateParam(paramName: string, paramValue: string | undefined): Date | undefined {\n\tif (!paramValue) {\n\t\treturn undefined;\n\t}\n\n\tconst date = new Date(paramValue);\n\tif (isNaN(date.getTime())) {\n\t\tthrow new Meteor.Error('error-roomId-param-invalid', `The \"${paramName}\" query parameter must be a valid date.`);\n\t}\n\n\treturn date;\n}\n\nconst emojiCustomListResponseSchema = ajv.compile<{\n\temojis: { update: IEmojiCustom[]; remove: WithId<RocketChatRecordDeleted<IEmojiCustom>>[] };\n}>({\n\ttype: 'object',\n\tproperties: {\n\t\temojis: {\n\t\t\ttype: 'object',\n\t\t\tproperties: {\n\t\t\t\tupdate: { type: 'array', items: { type: 'object' } },\n\t\t\t\tremove: { type: 'array', items: { type: 'object' } },\n\t\t\t},\n\t\t\trequired: ['update', 'remove'],\n\t\t},","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/emoji-custom.ts#L41-L77","documentation":"Thrown by GET emoji-custom.list when the updatedSince or _updatedAt query parameter cannot be parsed as a JavaScript Date (new Date(paramValue) yields NaN). The server needs a real date to build the MongoDB _updatedAt: { $gt: date } filter for incremental sync, so an unparseable value is rejected with HTTP 400. Note the error code is misleadingly named 'error-roomId-param-invalid' (legacy copy from rooms endpoints) even though it concerns date params on emoji-custom.list.","triggerScenarios":"Calling GET /api/v1/emoji-custom.list?updatedSince=31/12/2024 (DD/MM/YYYY, not parseable as date), ?updatedSince=yesterday, ?updatedSince=2024-13-45, or a double-encoded value like %272024-01-01%27 that arrives with quote characters. Passing an empty string does NOT trigger it (empty is treated as absent); only non-empty unparseable strings do.","commonSituations":"Client scripts formatting dates with locale-specific formats instead of ISO 8601; teams syncing emoji changes since a stored local timestamp; copy-pasting a timestamp from Mongo shell (e.g. ISODate(...) or epoch seconds as a bare number-string like 1718000000, which some JS engines reject); URL-encoding bugs that inject whitespace or quotes around the value.","solutions":["Send the date as ISO 8601 / RFC 3339 UTC, e.g. updatedSince=2024-12-31T23:59:59.000Z (new Date().toISOString() on the client)","If you do not need incremental sync, omit updatedSince and _updatedAt entirely - empty/absent params are skipped","Check the raw value that reaches the server (log this.queryParams) for stray quotes, spaces, or percent-encoding artifacts and URL-encode properly","If you store epoch seconds, convert before sending: new Date(epochMs).toISOString(), do not send the bare number string"],"exampleFix":"// before\nconst res = await sdk.get('emoji-custom.list', { updatedSince: '31/12/2024' });\n\n// after\nconst res = await sdk.get('emoji-custom.list', { updatedSince: new Date('2024-12-31T00:00:00Z').toISOString() });","handlingStrategy":"validation","validationCode":"function toIsoDate(value) {\n  if (!value) return undefined;\n  const ms = Date.parse(value);\n  if (Number.isNaN(ms)) throw new Error(`updatedSince is not a parseable date: ${value}`);\n  return new Date(ms).toISOString();\n}\n// use: sdk.get('emoji-custom.list', { updatedSince: toIsoDate(lastSync) })","typeGuard":"const isParsableDateString = (v: unknown): v is string =>\n  typeof v === 'string' && v.length > 0 && !Number.isNaN(Date.parse(v));","tryCatchPattern":"try { await sdk.get('emoji-custom.list', { updatedSince }); } catch (e) {\n  if (e.error === 'error-roomId-param-invalid') { /* re-send with new Date().toISOString() */ }\n}","preventionTips":["Always serialize dates with toISOString() at the HTTP boundary, never toLocaleString()","Centralize query-string building in one client helper that type-checks date fields","Treat empty string and absent as the same thing: skip the param instead of sending ''"],"tags":["rest-api","emoji-custom","date-validation","query-params"],"backgroundTag":"invalid-query-parameter","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}