RocketChat/Rocket.Chat · error · Meteor.Error

error-param-required

error-param-required

Error message

The "type" or "lastUpdate" parameters must be provided

What it means

Defensive assertion in getMessageHistory: after the plain channel-history fallback and the lastUpdate path, the function requires 'type' to proceed with cursor pagination. In the shipped control flow every parameter combination that lacks lastUpdate is captured by the earlier fallback (line 271), so this throw fires only when a caller bypasses or refactors that fallback — e.g. a direct caller of getMessageHistory with a changed branch order. Note the related trap: passing count: null with a cursor makes hasCursorPagination false and silently falls back to plain history.

Source

Thrown at apps/meteor/server/publications/messages.ts:280

	// `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);
};

Meteor.methods<ServerMethods>({
	async 'messages/get'(
		rid,
		{ lastUpdate, latestDate = new Date(), oldestDate, inclusive = false, count = 20, unreads = false, next, previous, type },
	) {
		check(rid, String);

		const fromId = Meteor.userId();

		if (!fromId) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'messages/get' });
		}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Provide 'type' ("UPDATED" or "DELETED") together with next/previous and a non-null count
  2. Provide 'lastUpdate' to select the sync mode
  3. Keep the plain-history fallback in place if you refactor this function

Example fix

// before
await getMessageHistory(rid, uid, { next, count: null });

// after
await getMessageHistory(rid, uid, { next, type: 'UPDATED', count: 50 });
Defensive patterns

Strategy: validation

Validate before calling

const mode = params.lastUpdate ? 'sync' : (params.next || params.previous) && params.type && params.count != null ? 'cursor' : 'history';
if (mode === 'cursor' && !params.type) throw new Error('type is required for cursor pagination');
if (mode === 'cursor') delete params.count === null && delete params.count;

Type guard

type PaginationMode = { mode: 'history' } | { mode: 'sync'; lastUpdate: Date } | { mode: 'cursor'; type: 'UPDATED' | 'DELETED'; cursor?: string; count: number };

Try / catch

try { await getMessageHistory(rid, uid, params); } catch (e) { if (e.error === 'error-param-required') { /* supply type or lastUpdate per desired mode */ } }

Prevention

When it happens

Trigger: Direct server-side calls to getMessageHistory with a parameter set that no longer matches any mode after local refactors; payloads where count is explicitly null so hasCursorPagination stays false while lastUpdate is absent and the fallback was skipped.

Common situations: Custom branches of Rocket.Chat that reorder the mode checks; code that copies getMessageHistory into another service without the line-271 fallback.

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


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