RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-param

error-invalid-param

Error message

updatedSince must be a valid date string

What it means

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.

Solutions

  1. Send new Date(lastSync).toISOString() and encodeURIComponent it
  2. Persist the server's ISO strings (e.g. role._updatedAt) verbatim as your sync cursor rather than reformatting
  3. Add a client-side Date.parse check before the call so bad cursors fail locally with a clear message

Example fix

// before
await sdk.get('roles.sync', { updatedSince: lastSync }); // '2024/05/01 3 pm'

// after
const cursor = new Date(lastSyncMs).toISOString();
if (Number.isNaN(Date.parse(cursor))) throw new Error('bad sync cursor');
await sdk.get('roles.sync', { updatedSince: cursor });
Defensive patterns

Strategy: validation

Validate before calling

const cursor = new Date(lastSyncMs).toISOString();
if (updatedSinceProvided && Number.isNaN(Date.parse(cursor))) throw new Error('bad updatedSince cursor');
await sdk.get('roles.sync', updatedSinceProvided ? { updatedSince: encodeURIComponent(cursor) } : {});

Type guard

const isParseableDate = (v: unknown): v is string =>
  typeof v === 'string' && !Number.isNaN(Date.parse(v));

Try / catch

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.

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/86ef867de50e5839. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/server/api/v1/roles.ts:103

								update: { type: 'array', items: { $ref: '#/components/schemas/IRole' } },
								remove: { type: 'array', items: { $ref: '#/components/schemas/IRole' } },
							},
							required: ['update', 'remove'],
						},
						success: { type: 'boolean', enum: [true] },
					},
					required: ['roles', 'success'],
					additionalProperties: false,
				}),
				400: validateBadRequestErrorResponse,
				401: validateUnauthorizedErrorResponse,
			},
		},
		async function action() {
			const { updatedSince } = this.queryParams;

			if (updatedSince && Number.isNaN(Date.parse(updatedSince))) {
				throw new Meteor.Error('error-invalid-param', 'updatedSince must be a valid date string');
			}

			return API.v1.success({
				roles: {
					update: await Roles.findByUpdatedDate(new Date(updatedSince || 0)).toArray(),
					remove: await Roles.trashFindDeletedAfter(new Date(updatedSince || 0)).toArray(),
				},
			});
		},
	)
	.post(
		'roles.addUserToRole',
		{
			authRequired: true,
			body: isRoleAddUserToRoleProps,
			response: {
				200: ajv.compile<{ role: IRole }>({
					type: 'object',

View on GitHub (pinned to b2c16d5842)