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
- 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
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
- 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
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
- error-param-not-provided
- error-roomId-param-invalid
- error-invalid-roleId
- error-invalid-user
- error-not-allowed
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)