{"record":{"id":"86ef867de50e5839","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-param-86ef86","errorCode":"error-invalid-param","errorMessage":"updatedSince must be a valid date string","messagePattern":"updatedSince must be a valid date string","errorType":"exception","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/roles.ts","lineNumber":103,"sourceCode":"\t\t\t\t\t\t\t\tupdate: { type: 'array', items: { $ref: '#/components/schemas/IRole' } },\n\t\t\t\t\t\t\t\tremove: { type: 'array', items: { $ref: '#/components/schemas/IRole' } },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\trequired: ['update', 'remove'],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsuccess: { type: 'boolean', enum: [true] },\n\t\t\t\t\t},\n\t\t\t\t\trequired: ['roles', '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 { updatedSince } = this.queryParams;\n\n\t\t\tif (updatedSince && Number.isNaN(Date.parse(updatedSince))) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-param', 'updatedSince must be a valid date string');\n\t\t\t}\n\n\t\t\treturn API.v1.success({\n\t\t\t\troles: {\n\t\t\t\t\tupdate: await Roles.findByUpdatedDate(new Date(updatedSince || 0)).toArray(),\n\t\t\t\t\tremove: await Roles.trashFindDeletedAfter(new Date(updatedSince || 0)).toArray(),\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t)\n\t.post(\n\t\t'roles.addUserToRole',\n\t\t{\n\t\t\tauthRequired: true,\n\t\t\tbody: isRoleAddUserToRoleProps,\n\t\t\tresponse: {\n\t\t\t\t200: ajv.compile<{ role: IRole }>({\n\t\t\t\t\ttype: 'object',","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/roles.ts#L85-L121","documentation":"Thrown by GET /api/v1/roles.sync when the optional `updatedSince` query param is present but Number.isNaN(Date.parse(updatedSince)) — the string cannot be parsed as a date. The endpoint returns roles updated or trashed after that timestamp; sending anything Date.parse rejects ('epoch', '2024-13-01', a '+'-mangled ISO string) aborts with error-invalid-param before the queries run.","triggerScenarios":"GET /api/v1/roles.sync?updatedSince=<bad> with a locale-formatted date ('05/01/2024'), a bare epoch number as a string with suffixes, or an ISO timestamp whose timezone '+' was decoded to a space by the query parser. Omitting the param syncs everything and never triggers this.","commonSituations":"Sync clients persisting human-readable timestamps instead of ISO strings; encodeURIComponent skipped so '+00:00' becomes ' 00:00'; lastSync values coming from a different API's date format being reused verbatim.","solutions":["Send new Date(lastSync).toISOString() and encodeURIComponent it","Persist the server's ISO strings (e.g. role._updatedAt) verbatim as your sync cursor rather than reformatting","Add a client-side Date.parse check before the call so bad cursors fail locally with a clear message"],"exampleFix":"// before\nawait sdk.get('roles.sync', { updatedSince: lastSync }); // '2024/05/01 3 pm'\n\n// after\nconst cursor = new Date(lastSyncMs).toISOString();\nif (Number.isNaN(Date.parse(cursor))) throw new Error('bad sync cursor');\nawait sdk.get('roles.sync', { updatedSince: cursor });","handlingStrategy":"validation","validationCode":"const cursor = new Date(lastSyncMs).toISOString();\nif (updatedSinceProvided && Number.isNaN(Date.parse(cursor))) throw new Error('bad updatedSince cursor');\nawait sdk.get('roles.sync', updatedSinceProvided ? { updatedSince: encodeURIComponent(cursor) } : {});","typeGuard":"const isParseableDate = (v: unknown): v is string =>\n  typeof v === 'string' && !Number.isNaN(Date.parse(v));","tryCatchPattern":"catch 'error-invalid-param' from roles.sync, rebuild the cursor from the raw epoch with toISOString(), and retry exactly once; a second failure means the cursor source itself is corrupt.","preventionTips":["Persist sync cursors as ISO strings or epoch millis","Never reuse date strings from other APIs verbatim","Unit-test cursor formatting with timezone-carrying values"],"tags":["roles","validation","date","query-params","rest-api"],"backgroundTag":"invalid-date-format","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"}