RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-roleId

error-invalid-roleId

Error message

error-invalid-roleId

What it means

Thrown by GET /api/v1/roles.getUsersInRole when Roles.findOneById(role) returns null. Critically this lookup is by _id only — unlike roles.delete, which accepts id OR name. Passing a human-readable role name like 'admin' or 'moderator' here will always fail with error-invalid-roleId even though the role exists.

Solutions

  1. Resolve the name to an _id first: GET /api/v1/roles.list returns every role with both fields
  2. Use the 17-char role _id in the role param
  3. If the id came from config, refresh it against roles.list after workspace rebuilds

Example fix

// before
await sdk.get('roles.getUsersInRole', { role: 'admin' }); // name → error

// after
const { roles } = await sdk.get('roles.list');
const target = roles.find((r) => r.name === 'admin');
if (!target) throw new Error('unknown role name');
await sdk.get('roles.getUsersInRole', { role: target._id });
Defensive patterns

Strategy: validation

Validate before calling

// resolve to the role's _id before querying users
const { roles } = await sdk.get('roles.list');
const target = roles.find((r) => r._id === roleParam || r.name === roleParam);
if (!target) throw new Error(`unknown role: ${roleParam}`);
await sdk.get('roles.getUsersInRole', { role: target._id });

Type guard

const isRoleId = (v: unknown): v is string =>
  typeof v === 'string' && /^[A-Za-z0-9]{17}$/.test(v);

Try / catch

catch 'error-invalid-roleId', re-resolve the param against roles.list (the role may have been renamed/deleted), and retry once with the fresh _id.

Prevention

When it happens

Trigger: GET /api/v1/roles.getUsersInRole?role=admin (a name, not an id); a deleted custom role's id still referenced by cached scripts; a typo'd or truncated role _id.

Common situations: Code written against roles.delete (name-friendly) reused for getUsersInRole; role ids hardcoded per environment and stale after a re-install; names and ids conflated in configuration files.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/307d2f3962f1a4d4. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/server/api/v1/roles.ts:200

				username: 1,
				emails: 1,
				avatarETag: 1,
				createdAt: 1,
				_updatedAt: 1,
			};

			if (!role) {
				throw new Meteor.Error('error-param-not-provided', 'Query param "role" is required');
			}
			if (roomId && !(await hasPermissionAsync(this.user, 'view-other-user-channels'))) {
				throw new Meteor.Error('error-not-allowed', 'Not allowed');
			}

			const options = { projection: { _id: 1 } };
			const roleData = await Roles.findOneById<Pick<IRole, '_id'>>(role, options);

			if (!roleData) {
				throw new Meteor.Error('error-invalid-roleId');
			}

			const { cursor, totalCount } = await getUsersInRolePaginated(roleData._id, roomId, {
				limit: count,
				sort: { username: 1 },
				skip: offset,
				projection,
			});

			const [users, total] = await Promise.all([cursor.toArray(), totalCount]);

			return API.v1.success({ users, total });
		},
	)
	.post(
		'roles.delete',
		{
			authRequired: true,

View on GitHub (pinned to b2c16d5842)