RocketChat/Rocket.Chat · error · Error

team-does-not-exist

Error message

team-does-not-exist

What it means

Thrown by TeamService.addMembers (apps/meteor/server/services/team/service.ts:713) when Team.findOneById(teamId, { projection: { roomId: 1 } }) returns null — no team with that ID. The roomId projection is needed because members are added by joining the team's main channel via addUserToRoom. Over REST, teams.addMembers resolves the team first and returns its own 'team-does-not-exist' failure, so seeing the service's throw means a direct call or a delete race.

Source

Thrown at apps/meteor/server/services/team/service.ts:713

		}

		return {
			total: await totalCount,
			records: results,
		};
	}

	async addMembers(uid: string, teamId: string, members: Array<ITeamMemberParams>): Promise<void> {
		const createdBy = (await Users.findOneById(uid, { projection: { username: 1 } })) as Pick<IUser, '_id' | 'username'>;
		if (!createdBy) {
			throw new Error('invalid-user');
		}

		const team = await Team.findOneById<Pick<ITeam, 'roomId'>>(teamId, {
			projection: { roomId: 1 },
		});
		if (!team) {
			throw new Error('team-does-not-exist');
		}

		for await (const member of members) {
			const user = (await Users.findOneById(member.userId, { projection: { username: 1 } })) as Pick<IUser, '_id' | 'username'>;
			await addUserToRoom(team.roomId, user, createdBy, { skipSystemMessage: false });

			if (member.roles) {
				const isRoleAddedToTeam = await this.addRolesToMember(teamId, member.userId, member.roles);
				const isRoleAddedToSubscription = await this.addRolesToSubscription(team.roomId, member.userId, member.roles);
				if (settings.get<boolean>('UI_DisplayRoles') && isRoleAddedToTeam && isRoleAddedToSubscription) {
					member.roles.forEach((role) => {
						void api.broadcast('user.roleUpdate', {
							type: 'added',
							_id: role,
							u: {
								_id: user._id,
								username: user.username,
							},

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Re-resolve the team immediately before adding members and abort on null
  2. In long-running sync jobs, catch this error per-team and log/skip rather than aborting the whole run
  3. Over REST, rely on the endpoint's team-does-not-exist response and refresh the team list in the client

Example fix

// before
await Team.addMembers(uid, staleTeamId, members); // throws team-does-not-exist

// after
const team = await Team.findOneById(teamId, { projection: { roomId: 1 } });
if (!team) {
	throw new Error('team-does-not-exist');
}
await Team.addMembers(uid, team._id, members);
Defensive patterns

Strategy: try-catch

Validate before calling

const team = await Team.findOneById(teamId, { projection: { roomId: 1 } });
if (!team) {
	throw new Error('team-does-not-exist');
}
await Team.addMembers(uid, team._id, members);

Try / catch

try {
	await Team.addMembers(uid, teamId, members);
} catch (e) {
	if (e instanceof Error && e.message === 'team-does-not-exist') {
		// team removed mid-sync — skip this batch entry
	}
	throw e;
}

Prevention

When it happens

Trigger: Direct Team.addMembers(uid, staleTeamId, members); team deleted between the endpoint's getTeamByIdOrName resolution and the service lookup; mistyped IDs; teams on another workspace.

Common situations: Bulk member-sync jobs running while teams are being reorganized; UI holding a stale team reference after deletion; captured request replay against a different database.

Related errors


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