RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
The required "userId" or "username" param provided does not match any users
What it means
Thrown by getUserFromParams, the shared REST v1 helper that resolves a user from request params. Params are checked in priority order: userId (exact _id lookup), then username, then user (both case-insensitive username lookups). If one param was supplied but no user document matches it, the helper throws error-invalid-user. This is a 'value supplied but nothing found' error, distinct from error-user-param-not-provided which fires when no param is given at all.
Source
Thrown at apps/meteor/server/api/lib/getUserFromParams.ts:35
: Pick<IUser, '_id' | 'username' | 'name' | 'status' | 'statusDefault' | 'statusText' | 'statusSource' | 'statusExpiresAt' | 'roles'>
> {
let user;
const projection = full
? {}
: { username: 1, name: 1, status: 1, statusDefault: 1, statusText: 1, statusSource: 1, statusExpiresAt: 1, roles: 1 };
if (params.userId?.trim()) {
user = await Users.findOneById(params.userId, { projection });
} else if (params.username?.trim()) {
user = await Users.findOneByUsernameIgnoringCase(params.username, { projection });
} else if (params.user?.trim()) {
user = await Users.findOneByUsernameIgnoringCase(params.user, { projection });
} else {
throw new Meteor.Error('error-user-param-not-provided', 'The required "userId" or "username" param was not provided');
}
if (!user) {
throw new Meteor.Error('error-invalid-user', 'The required "userId" or "username" param provided does not match any users');
}
return user;
}
export async function getUserListFromParams(params: {
userId?: string;
username?: string;
user?: string;
userIds?: string[];
usernames?: string[];
}): Promise<Pick<IUser, '_id' | 'username'>[]> {
// if params.userId is provided, include it as well
const soleUser = params.userId || params.username || params.user;
let userListParam = params.userIds || params.usernames || [];
userListParam.push(soleUser || '');
userListParam = userListParam.filter(Boolean);
View on GitHub (pinned to b2c16d5842)
Solutions
- Verify the user exists first with GET /api/v1/users.info?username=<value> (or ?userId=) to see which identifier resolves
- Make sure usernames go into the username or user param and Mongo _ids into userId — userId is matched by _id only, not by name
- Trim and URL-decode the value; check for invisible characters or broken JSON encoding in the query string
- If the user was deleted or lives on a federated server, re-create/resolve the account or use its local username
Example fix
// before GET /api/v1/users.info?userId=rocket.cat // username wrongly used as _id // after GET /api/v1/users.info?username=rocket.cat // or ?userId=aobEdbYhXfu5hkeqG
Defensive patterns
Strategy: validation
Validate before calling
async function resolveUserIdent(client, userIdOrName: string): Promise<string> {
// users.info accepts either param and 404s cleanly when absent
const r = await client.get('/api/v1/users.info', { params: { userId: userIdOrName } });
if (r.ok) return r.data.user._id;
const byName = await client.get('/api/v1/users.info', { params: { username: userIdOrName } });
if (byName.ok) return byName.data.user._id;
throw new Error(`no user matches ${userIdOrName}`);
} Type guard
const isUserRef = (v: unknown): v is { userId?: string; username?: string; user?: string } =>
typeof v === 'object' && v !== null && !Array.isArray(v) &&
Object.values(v).some((x) => typeof x === 'string' && x.trim() !== ''); Try / catch
try {
await client.get('/api/v1/channels.info', { params: { username } });
} catch (e: any) {
if (e?.response?.data?.errorType === 'error-invalid-user') {
// treat as 404: identifier valid but no such user
throw new NotFoundError(`user ${username} not found`);
}
throw e;
} Prevention
- Normalize all user references to _id at ingestion time and store the source of the identifier
- Never put a username into the userId param — userId is matched by _id only
- Wrap user-dependent calls with a users.info existence probe when identifiers come from user input or stale caches
When it happens
Trigger: Calling any REST v1 endpoint backed by this helper (users.info-style flows in apps/meteor/server/api/v1/{users,channels,groups,rooms,misc,roles}.ts) with a userId that is not a real user _id, or a username/user value that matches no username. Typical: passing the username 'rocket.cat' inside the userId param (it is then looked up as an _id and fails), quoting the ID with stray whitespace, or referencing a user that was deleted.
Common situations: Client cached a stale userId across a workspace reset or user deletion; copy-pasting a username where an _id belongs; federation setups where the user exists on another server but not locally; renamed users when the old username was stored.
Related errors
- error-users-params-not-provided
- query must be an object
- invalid-user
- error-invalid-sort
- error-invalid-fields
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/97ce75f20986f960.
Report an issue: GitHub.