RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-arguments
error-invalid-arguments
Error message
Invalid arguments
What it means
Thrown by addUsersToRoomMethod() in apps/meteor/server/meteor-methods/rooms/addUsersToRoom.ts:81 when Array.isArray(data.users) is false. The users payload must be an array of usernames; the method then maps over it (data.users.map) in a Promise.all, so a non-array would crash the loop if not rejected here. Note this check runs after the permission checks, so an unauthorized caller gets error-not-allowed first.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/addUsersToRoom.ts:81
let canAddUser = false;
if (userInRoom && (await hasPermissionAsync(userId, 'add-user-to-joined-room', room._id))) {
canAddUser = true;
} else if (room.t === 'c' && (await hasPermissionAsync(userId, 'add-user-to-any-c-room'))) {
canAddUser = true;
} else if (room.t === 'p' && (await hasPermissionAsync(userId, 'add-user-to-any-p-room'))) {
canAddUser = true;
}
// Adding wasn't allowed
if (!canAddUser) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'addUsersToRoom',
});
}
// Missing the users to be added
if (!Array.isArray(data.users)) {
throw new Meteor.Error('error-invalid-arguments', 'Invalid arguments', {
method: 'addUsersToRoom',
});
}
await beforeAddUsersToRoom.run({ usernames: data.users, inviter: user }, room);
await Promise.all(
data.users.map(async (username) => {
const sanitizedUsername = sanitizeUsername(username);
const newUser = await Users.findOneByUsernameIgnoringCase(sanitizedUsername);
if (!newUser) {
throw new Meteor.Error('error-user-not-found', 'User not found', {
method: 'addUsersToRoom',
});
}
const subscription = await Subscriptions.findOneByRoomIdAndUserId(data.rid, newUser._id);View on GitHub (pinned to b2c16d5842)
Solutions
- Normalize to an array at the boundary: const users = Array.isArray(x) ? x : [x].filter(Boolean).
- Validate the payload shape before calling (Match/Object schema or a manual typeof check).
- If porting REST logic, remember the method takes usernames (strings), not user IDs or user objects.
- Type the payload as { rid: string; users: string[] } at your call site so the compiler catches scalar mistakes.
Example fix
// before
await addUsersToRoomMethod(uid, { rid, users: payload.username });
// after
const users = Array.isArray(payload.users) ? payload.users : [payload.username].filter(Boolean);
await addUsersToRoomMethod(uid, { rid, users }); Defensive patterns
Strategy: type-guard
Validate before calling
if (!Array.isArray(data.users)) {
data.users = [data.users].filter(Boolean);
} Type guard
const isUsernameArray = (v: unknown): v is string[] => Array.isArray(v) && v.every((x) => typeof x === 'string');
Try / catch
try {
await addUsersToRoomMethod(uid, { rid, users });
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-invalid-arguments') {
// normalize users to string[] and retry once
}
} Prevention
- Validate the payload shape (Match/Object schema) at the boundary.
- Type call sites as { rid: string; users: string[] }. Wrap single values into arrays before passing them to bulk APIs.
When it happens
Trigger: Passing data.users as a single username string, undefined (key missing), null, or an object; API shims mapping a REST body {username} directly to {users}; JSON inputs where users is an object map rather than an array.
Common situations: Client refactors renaming the field; type drift between callers written in JS and the TS signature; wrapping/unwrapping payloads incorrectly in automation scripts; the single-user 'addUserToRoom' wrapper being bypassed and the bulk method called with a scalar.
Related errors
- error-invalid-room
- error-invalid-arguments
- error-invalid-arguments
- error-invalid-room
- error-invalid-room
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/012ca8aa07dce565.
Report an issue: GitHub.