RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
Invalid user
What it means
Thrown by findDirectMessageRoom (apps/meteor/server/api/v1/im.ts:56) when Users.findOneById(uid) returns null: the request was resolved to a userId, but no user document with that _id exists in the `users` collection. The credentials pair (token + userId) points at an account that has been deleted or never existed.
Solutions
- Re-authenticate: log in as an existing user (or mint a new personal access token) and retry with the new X-User-Id / X-Auth-Token pair
- Confirm the user exists: GET /api/v1/users.info?userId=... as an admin
- If a deletion job removed the user, also revoke/invalidate that user's tokens so future calls fail with a proper auth error
- In tests, recreate user fixtures and re-derive tokens after every database reset
Example fix
// before — token belongs to a deleted user
const headers = { 'X-User-Id': deletedUserId, 'X-Auth-Token': staleToken };
await get('/api/v1/im.messages', { username: 'alice' }, { headers }); // error-invalid-user
// after — validate credentials once, then re-login on failure
const me = await get('/api/v1/me', {}, { headers });
if (!me.success) {
const { data } = await post('/api/v1/login', { user, password });
headers['X-User-Id'] = data.userId;
headers['X-Auth-Token'] = data.authToken;
}
await get('/api/v1/im.messages', { username: 'alice' }, { headers }); Defensive patterns
Strategy: validation
Validate before calling
const me = await fetch('/api/v1/me', { headers: { 'X-Auth-Token': token, 'X-User-Id': uid } });
if (me.status === 401 || (me.ok && (await me.json()).success === false)) {
// token/user pair no longer resolves to a live account — re-login before any im.* call
throw new Error('credentials stale: re-authenticate');
} Try / catch
try {
await get('/api/v1/im.messages', { roomId });
} catch (e) {
if (e?.body?.errorType === 'error-invalid-user' && 'method' in (e.body?.details ?? {})) {
// userId behind the token no longer exists: drop cached credentials, re-login or abort
await invalidateCachedCredentials();
}
throw e;
} Prevention
- Validate credentials with GET /api/v1/me at client startup and after any 401-ish failure
- Invalidate tokens server-side whenever users are deleted
- Never cache user tokens across database resets/restores in test environments
When it happens
Trigger: The authenticated user was deleted (admin action, GDPR/retention purge) while their REST token or personal access token was still being sent; a hand-crafted X-User-Id paired with a token that no longer maps to a live user; database restored from a backup missing that user record.
Common situations: Long-lived personal access tokens or OAuth tokens outliving their accounts; test suites with stale fixture user IDs after a DB reset; user-deletion jobs that forget to revoke tokens, so clients get this error instead of a clean 401.
Understand the failure class
Background: error-invalid-user: "Invalid user" errors in Rocket.Chat — what they mean and how to fix them — this error's family across 2 libraries.
Related errors
- error-challenge-expired
- error-challenge-not-found
- error-invalid-challenge-method
- error-invalid-user
- error-invalid-user
AI-assisted analysis of RocketChat/Rocket.Chat@e4b8178b20 (2026-08-18).
Data as JSON: /api/errors/0d7726f345325370.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/server/api/v1/im.ts:59
import type { ExtractRoutesFromAPI } from '../ApiClass';
import { API } from '../api';
import type { TypedAction } from '../definition';
import { addUserToFileObj } from '../lib/addUserToFileObj';
import { composeRoomWithLastMessage } from '../lib/composeRoomWithLastMessage';
import { getPaginationItems } from '../lib/getPaginationItems';
const findDirectMessageRoom = async (
keys: { roomId?: string; username?: string },
uid: string,
): Promise<{ room: IRoom; subscription: ISubscription | null }> => {
const nameOrId = 'roomId' in keys ? keys.roomId : keys.username;
if (typeof nameOrId !== 'string') {
throw new Meteor.Error('error-room-param-not-provided', 'Query param "roomId" or "username" is required');
}
const user = await Users.findOneById(uid);
if (!user) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'findDirectMessageRoom',
});
}
const room = await getRoomByNameOrIdWithOptionToJoin({
user,
nameOrId,
type: 'd',
});
if (!room || room?.t !== 'd') {
throw new Meteor.Error('error-room-not-found', 'The required "roomId" param provided does not match any direct message');
}
const subscription = await Subscriptions.findOne({ 'rid': room._id, 'u._id': uid });
return {
room,View on GitHub (pinned to e4b8178b20)