RocketChat/Rocket.Chat · error · Meteor.Error
error-fromTs-requires-lastUpdate
error-fromTs-requires-lastUpdate
Error message
The "fromTs" parameter can only be used together with "lastUpdate"
What it means
Thrown by getMessageHistory when 'fromTs' is passed without 'lastUpdate'. 'fromTs' only bounds the query on the lastUpdate sync path; cursor pagination and the plain channel-history fallback ignore it, so accepting it there would silently widen the result set. The server therefore rejects the combination instead of returning more data than requested.
Source
Thrown at apps/meteor/server/publications/messages.ts:266
if ((next || previous) && !type) {
throw new Meteor.Error('error-type-param-required', 'The "type" parameter is required when using the "next" or "previous" parameters');
}
if (next && previous) {
throw new Meteor.Error('error-cursor-conflict', 'You cannot provide both "next" and "previous" parameters');
}
if ((next || previous) && lastUpdate) {
throw new Meteor.Error(
'error-cursor-and-lastUpdate-conflict',
'The attributes "next", "previous" and "lastUpdate" cannot be used together',
);
}
// `fromTs` only bounds the query on the `lastUpdate` path; neither cursor pagination nor the channel
// history fallback honors it, so accepting it there would silently widen the result set.
if (fromTs && !lastUpdate) {
throw new Meteor.Error('error-fromTs-requires-lastUpdate', 'The "fromTs" parameter can only be used together with "lastUpdate"');
}
const hasCursorPagination = !!((next || previous) && count !== null && type);
if (!hasCursorPagination && !lastUpdate) {
return getChannelHistory({ rid, fromUserId: fromId, latest: latestDate, oldest: oldestDate, inclusive, count, unreads });
}
if (lastUpdate) {
return handleWithoutPagination(rid, lastUpdate, fromTs);
}
if (!type) {
throw new Meteor.Error('error-param-required', 'The "type" or "lastUpdate" parameters must be provided');
}
return handleCursorPagination(type, rid, count, next, previous);
};View on GitHub (pinned to b2c16d5842)
Solutions
- Add 'lastUpdate' to the same payload: fromTs is only honored as an additional lower bound on that path
- Drop 'fromTs' and use 'oldestDate' for plain channel-history bounding
- For cursor pagination, rely on the cursor token instead of fromTs
Example fix
// before
Meteor.call('messages/get', rid, { fromTs });
// after
Meteor.call('messages/get', rid, { lastUpdate, fromTs }); Defensive patterns
Strategy: validation
Validate before calling
if (params.fromTs && !params.lastUpdate) {
throw new Error('fromTs requires lastUpdate');
}
Meteor.call('messages/get', rid, params); Type guard
function isSyncParams(p: { fromTs?: Date; lastUpdate?: Date }): p is { fromTs: Date; lastUpdate: Date } {
return Boolean(p.lastUpdate && (!p.fromTs || p.fromTs instanceof Date));
} Try / catch
try { await Meteor.callAsync('messages/get', rid, params); } catch (e) { if (e.error === 'error-fromTs-requires-lastUpdate') { delete params.fromTs; /* retry or surface */ } } Prevention
- Document that fromTs is a sub-filter of the lastUpdate sync mode only
- Use oldestDate for plain-history time bounds
When it happens
Trigger: Meteor.call('messages/get', rid, { fromTs: new Date('2024-01-01') }) without lastUpdate; passing fromTs together with next/previous cursor pagination; forwarding a fromTs filter into the plain history fallback.
Common situations: A client adds a 'fetch messages since timestamp' filter assuming it applies to all modes; REST bridges mapping a 'since' query param to fromTs without mapping the corresponding lastUpdate field.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- error-cursor-and-lastUpdate-conflict
- error-param-required
- error-invalid-user
- error-invalid-room
- error-invalid-command
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/3c3944421d05e3e3.
Report an issue: GitHub.