RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-date

error-invalid-date

Error message

Invalid date

What it means

getChannelHistory validates that oldest, when provided, is a real Date instance using {}.toString.call(oldest) !== '[object Date]', and throws 'error-invalid-date' otherwise. DDP method params must carry actual Date objects (EJSON preserves them across the wire); an ISO string like '2024-01-01T00:00:00.000Z' or an epoch number fails this check even though it looks date-like.

Source

Thrown at apps/meteor/server/meteor-methods/messages/getChannelHistory.ts:74

	const room = await Rooms.findOneById(rid);
	if (!room) {
		return false;
	}

	// Make sure they can access the room
	if (!(await Authorization.canReadRoom(room, { _id: fromUserId }))) {
		return false;
	}

	// Ensure latest is always defined.
	if (latest === undefined) {
		latest = new Date();
	}

	// Verify oldest is a date if it exists

	if (oldest !== undefined && {}.toString.call(oldest) !== '[object Date]') {
		throw new Meteor.Error('error-invalid-date', 'Invalid date', { method: 'getChannelHistory' });
	}

	const hiddenSystemMessages = settings.get<MessageTypesValues[]>('Hide_System_Messages');

	const hiddenMessageTypes = getHiddenSystemMessages(room, hiddenSystemMessages);

	const options: Record<string, unknown> = {
		sort: {
			ts: -1,
		},
		skip: offset,
		limit: count,
	};

	const records =
		oldest === undefined
			? await Messages.findVisibleByRoomIdBeforeTimestampNotContainingTypes(
					rid,

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Pass Date objects: Meteor.call('getChannelHistory', { rid, oldest: new Date('2024-01-01T00:00:00.000Z') })
  2. If your API accepts strings, convert before invoking: oldest = new Date(oldest)
  3. Or use GET /v1/channels.history, whose date params are ISO strings parsed server-side (also the deprecation target)

Example fix

// before
Meteor.call('getChannelHistory', { rid, oldest: '2024-01-01T00:00:00.000Z' });

// after
Meteor.call('getChannelHistory', { rid, oldest: new Date('2024-01-01T00:00:00.000Z') });
Defensive patterns

Strategy: type-guard

Validate before calling

const oldestDate = typeof oldest === 'string' ? new Date(oldest) : oldest;
if (Number.isNaN(oldestDate?.getTime?.())) {
  throw new TypeError('oldest must be a parseable date');
}
Meteor.call('getChannelHistory', { rid, oldest: oldestDate });

Type guard

function isDate(value: unknown): value is Date {
  return {}.toString.call(value) === '[object Date]';
}
// usage: if (!isDate(oldest)) oldest = new Date(oldest);

Prevention

When it happens

Trigger: Meteor.call('getChannelHistory', { rid, oldest: '2024-01-01T00:00:00.000Z' }) — passing an ISO string or a timestamp number; params serialized with plain JSON.stringify instead of EJSON; raw form/URL inputs fed to the method.

Common situations: Porting code from the REST API (channels.history accepts ISO date strings) to the DDP method; wrappers that round-trip params through plain JSON; date pickers returning strings.

Related errors


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