{"record":{"id":"44fac02a4eef8772","repo":"RocketChat/Rocket.Chat","slug":"the-property-start-query-parameter-must-be-a","errorCode":null,"errorMessage":"The \"${property}.start\" query parameter must be a valid date.","messagePattern":"The \"(.+?)\\.start\" query parameter must be a valid date\\.","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/rooms.ts","lineNumber":16,"sourceCode":"import { LivechatRooms } from '@rocket.chat/models';\nimport { isGETLivechatRoomsParams } from '@rocket.chat/rest-typings';\n\nimport { API } from '../..';\nimport { findRooms } from './lib/rooms';\nimport { hasPermissionAsync } from '../../../lib/authorization/hasPermission';\nimport { getPaginationItems } from '../../lib/getPaginationItems';\n\nconst validateDateParams = (property: string, date?: string) => {\n\tlet parsedDate: { start?: string; end?: string } | undefined = undefined;\n\tif (date) {\n\t\tparsedDate = JSON.parse(date) as { start?: string; end?: string };\n\t}\n\n\tif (parsedDate?.start && isNaN(Date.parse(parsedDate.start))) {\n\t\tthrow new Error(`The \"${property}.start\" query parameter must be a valid date.`);\n\t}\n\tif (parsedDate?.end && isNaN(Date.parse(parsedDate.end))) {\n\t\tthrow new Error(`The \"${property}.end\" query parameter must be a valid date.`);\n\t}\n\treturn parsedDate;\n};\n\nconst isBoolean = (value?: string | boolean): boolean => value === 'true' || value === 'false' || typeof value === 'boolean';\n\nAPI.v1.addRoute(\n\t'livechat/rooms',\n\t{ authRequired: true, validateParams: isGETLivechatRoomsParams },\n\t{\n\t\tasync get() {\n\t\t\tconst { offset, count } = await getPaginationItems(this.queryParams);\n\t\t\tconst { sort, fields, query } = await this.parseJsonQuery();\n\t\t\tconst { agents, departmentId, open, tags, roomName, onhold, queued, units } = this.queryParams;\n\t\t\tconst { createdAt, customFields, closedAt } = this.queryParams;","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/omnichannel/rooms.ts#L1-L34","documentation":"Thrown by GET /api/v1/livechat/rooms when the JSON-encoded date-range query parameter (typically 'created' or 'closed', e.g. created={\"start\":\"...\",\"end\":\"...\"}) parses as JSON but its start value is not a parseable date — Date.parse(start) is NaN. The property name is interpolated into the message so the client knows which parameter failed.","triggerScenarios":"Passing created=%7B%22start%22%3A%222024-13-01%22%7D (invalid month), a start like '2024/31/12', an empty-ish or malformed string, or a timestamp with a bad timezone suffix; also passing a bare string instead of a JSON object when the code expects {start}.","commonSituations":"Clients building the filter with toISOString on invalid Date objects (NaN dates serialize to 'Invalid Date' or 'null'); locale-formatted dates (dd/mm/yyyy) from user-facing date pickers; hand-crafted query strings missing URL-encoding, which corrupts the JSON before it reaches the server.","solutions":["Generate the range programmatically: JSON.stringify({ start: d1.toISOString(), end: d2.toISOString() }) and encodeURIComponent it","Validate with Date.parse on the client before sending; skip the filter when the value is invalid","Use ISO-8601 (yyyy-MM-dd or full ISO timestamps); avoid locale-specific formats"],"exampleFix":"// before\nconst q = `created=${JSON.stringify({ start: '01/12/2024', end: '31/12/2024' })}`; // dd/mm/yyyy → NaN\n\n// after\nconst range = { start: new Date('2024-12-01').toISOString(), end: new Date('2024-12-31').toISOString() };\nif (Number.isNaN(Date.parse(range.start)) || Number.isNaN(Date.parse(range.end))) throw new Error('bad range');\nconst q = `created=${encodeURIComponent(JSON.stringify(range))}`;","handlingStrategy":"validation","validationCode":"function toRangeParam(d1, d2) {\n  const range = {};\n  if (d1 instanceof Date && !Number.isNaN(d1.getTime())) range.start = d1.toISOString();\n  if (d2 instanceof Date && !Number.isNaN(d2.getTime())) range.end = d2.toISOString();\n  return Object.keys(range).length ? encodeURIComponent(JSON.stringify(range)) : '';\n}","typeGuard":"function isValidRangeValue(v) {\n  return typeof v === 'string' && v.length > 0 && !Number.isNaN(Date.parse(v));\n}","tryCatchPattern":null,"preventionTips":["Only serialize Date objects that pass !isNaN(getTime())","Always use ISO-8601 from toISOString(), never locale strings","encodeURIComponent the whole JSON payload"],"tags":["omnichannel","livechat","query-params","date-validation","rest-api"],"backgroundTag":"query-parameter-validation-failed","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"}