RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
Invalid user
What it means
First guard in the exported createChannelMethod helper: the userId argument itself is falsy. The createChannel DDP wrapper resolves and checks Meteor.userId() on its own, so this specific throw is for internal/server-side callers that passed undefined/null/'' as the user id.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/createChannel.ts:36
customFields?: Record<string, any>,
extraData?: Record<string, any>,
): ICreatedRoom;
}
}
export const createChannelMethod = async (
userId: string,
name: string,
members: string[],
readOnly = false,
customFields?: Record<string, any>,
extraData: Record<string, any> = {},
excludeSelf = false,
) => {
check(name, String);
check(members, Match.Optional([String]));
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'createChannel' });
}
const user = await Users.findOneById(userId, { projection: { services: 0 } });
if (!user?.username) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'createChannel' });
}
if (extraData.teamId) {
const team = await Team.findOneById<Pick<ITeam, '_id' | 'roomId'>>(extraData.teamId, { projection: { roomId: 1 } });
if (!team) {
throw new Meteor.Error('error-team-not-found', 'The "teamId" param provided does not match any team', { method: 'createChannel' });
}
if (!(await hasPermissionAsync(userId, 'create-team-channel', team.roomId))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'createChannel' });
}
} else if (!(await hasPermissionAsync(userId, 'create-c'))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'createChannel' });
}View on GitHub (pinned to b2c16d5842)
Solutions
- Pass an explicit, existing user _id as the first argument.
- Capture Meteor.userId() inside the request context and propagate it into async continuations that call the helper.
- Where no human actor exists, use a designated admin/system account or call the createRoom service directly.
Example fix
// before
createChannelMethod(Meteor.userId(), name, members); // null outside a request
// after
const uid = Meteor.userId();
if (!uid) {
throw new Error('createChannelMethod requires a user id');
}
createChannelMethod(uid, name, members); Defensive patterns
Strategy: validation
Validate before calling
if (!uid) {
throw new Error('createChannelMethod requires a real user id');
}
await createChannelMethod(uid, name, members); Type guard
const isNonEmptyUserId = (uid: string | null | undefined): uid is string => typeof uid === 'string' && uid.length > 0;
Try / catch
try {
await createChannelMethod(uid, name, members);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-invalid-user') {
// internal caller bug: uid was falsy - fix the call site, do not retry
throw new Error('createChannelMethod called without a user id');
}
throw e;
} Prevention
- Pass the uid explicitly when reusing createChannelMethod outside the DDP wrapper.
- Capture Meteor.userId() inside the request and propagate it into async continuations (Meteor.bindEnvironment) instead of reading it later.
- Give the helper's arguments explicit types so a missing uid fails at compile time.
When it happens
Trigger: Custom server code imports createChannelMethod and passes a uid variable that is undefined (Meteor.userId() read outside a request, wrong destructuring, or an argument-order mistake in the long positional signature name/members/readOnly/customFields/extraData/excludeSelf).
Common situations: Logic ported into workers/jobs where no user context exists; refactors that drop or shift arguments; code copied from the wrapper with uid forgotten.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/f9f2faeec2f2d809.
Report an issue: GitHub.