RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
Invalid user
What it means
loadNextMessages requires an authenticated caller: Meteor.userId() returning null throws error-invalid-user before rid or room access is evaluated. The method fetches messages following a given timestamp and has no anonymous mode (unlike loadHistory).
Source
Thrown at apps/meteor/server/meteor-methods/messages/loadNextMessages.ts:23
import { Meteor } from 'meteor/meteor';
import { canAccessRoomIdAsync } from '../../lib/authorization/canAccessRoom';
import { normalizeMessagesForUser } from '../../lib/utils/lib/normalizeMessagesForUser';
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
loadNextMessages(rid: IRoom['_id'], end?: Date, limit?: number): Promise<{ messages: IMessage[] }>;
}
}
Meteor.methods<ServerMethods>({
async loadNextMessages(rid, end, limit = 20) {
check(rid, String);
check(limit, Number);
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'loadNextMessages',
});
}
if (!rid) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'loadNextMessages' });
}
const fromId = Meteor.userId();
if (!fromId || !(await canAccessRoomIdAsync(rid, fromId))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'loadNextMessages' });
}
let records;
if (end) {
records = await Messages.findVisibleByRoomIdAfterTimestamp(rid, end, true, {
sort: {View on GitHub (pinned to b2c16d5842)
Solutions
- Check Meteor.userId() before calling and gate the UI on login state
- Re-authenticate on session expiry, then retry the fetch
- For scripts, log in over DDP before invoking the method
Example fix
// before
const { messages } = await Meteor.callAsync('loadNextMessages', rid, end, limit);
// after
if (!Meteor.userId()) {
// require login before paging newer messages
} else {
const { messages } = await Meteor.callAsync('loadNextMessages', rid, end, limit);
} Defensive patterns
Strategy: validation
Validate before calling
if (!Meteor.userId()) {
// loadNextMessages requires a logged-in user
} Try / catch
try {
const { messages } = await Meteor.callAsync('loadNextMessages', rid, end, limit);
} catch (error) {
if (error instanceof Meteor.Error && error.error === 'error-invalid-user') {
// session expired — re-authenticate and retry once
} else {
throw error;
}
} Prevention
- Disable 'load newer messages' controls in logged-out states
- Cancel in-flight paging calls on logout
- For DDP scripts, complete login before calling
When it happens
Trigger: Meteor.call('loadNextMessages', rid, end, limit) from a logged-out tab, with an invalidated resume token, or from a DDP client that never performed a login.
Common situations: Expired sessions in long-lived tabs; 'load more' buttons firing after logout; automation scripts calling the method without authenticating.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/4d8cc103df794307.
Report an issue: GitHub.