RocketChat/Rocket.Chat · error · Meteor.Error
error-cursor-conflict
error-cursor-conflict
Error message
You cannot provide both "next" and "previous" parameters
What it means
Cursor pagination in messages/get is one-directional per request: supplying both next and previous throws Meteor.Error 'error-cursor-conflict' before any data is fetched. Each response cursor pair indicates where to continue in each direction, but only one may be used per call.
Source
Thrown at apps/meteor/server/publications/messages.ts:253
}
| false
| IMessage[]
| { messages: IMessage[]; firstUnread?: any; unreadNotLoaded?: number }
> => {
if (!(await canAccessRoomIdAsync(rid, fromId))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'messages/get' });
}
if (type && !['UPDATED', 'DELETED'].includes(type)) {
throw new Meteor.Error('error-type-param-not-supported', 'The "type" parameter must be either "UPDATED" or "DELETED"');
}
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) {View on GitHub (pinned to b2c16d5842)
Solutions
- Send only the direction you are paging: next to go forward, previous to go backward
- Keep a single active cursor in state, not both
- Treat a null cursor as 'no more pages in that direction' and omit it from the next request
Example fix
// before
Meteor.call('messages/get', rid, { type, next: cursor.next ?? undefined, previous: cursor.previous ?? undefined }); // both set -> error-cursor-conflict
// after
const paging = direction === 'older' ? { next: cursor.next ?? undefined } : { previous: cursor.previous ?? undefined };
Meteor.call('messages/get', rid, { type, ...paging }); Defensive patterns
Strategy: validation
Validate before calling
const hasSingleCursorDirection = (params: { next?: string; previous?: string }): boolean =>
!(params.next && params.previous); Type guard
const isSingleDirectionPaging = (p: unknown): p is { next?: string; previous?: string } => {
const v = p as { next?: string; previous?: string };
return !(v.next && v.previous);
}; Prevention
- Send exactly one cursor per request — the direction you are paging in
- Do not spread a stored cursor object into the request; pick one field explicitly
- Treat null cursors from responses as end-of-pages and omit them from subsequent requests
When it happens
Trigger: Calling messages/get with both next and previous set — most often a client echoing the whole response.cursor { next, previous } object verbatim into the next request.
Common situations: Mirroring the cursor object from a previous response; merging paging params from two branches of UI state (infinite scroll up + down); request builders that spread all stored params unconditionally.
Related errors
- Invalid Date
- error-cursor-not-found
- error-type-param-not-supported
- error-type-param-required
- error-cursor-and-lastUpdate-conflict
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/62da2bb4d6827116.
Report an issue: GitHub.