RocketChat/Rocket.Chat · error · Error
invalid-agent
Error message
invalid-agent
What it means
Thrown by GET /api/v1/livechat/agent.info/:rid/:token when the visitor token and room both resolve but no agent can be derived. The handler computes `room?.servedBy && (await findAgent(room.servedBy._id))`, which is falsy in two cases: the room has no `servedBy` yet (chat still queued/unassigned), or `findAgent` (normalizeAgent over the user id in `servedBy._id`) cannot resolve a live omnichannel agent.
Solutions
- If the chat was just created, treat the error as 'not assigned yet': wait for the agent-joined callback/room update (or poll livechat/room) and only call agent.info once servedBy is present.
- Fetch the room (e.g. livechat/room with the token) and confirm room.servedBy exists before requesting agent info.
- If servedBy exists but the error persists, verify the user behind servedBy._id still exists, is active, and is registered as a livechat agent; reassign the room if not.
- On the widget, degrade gracefully (hide the agent header) instead of surfacing the raw error.
Example fix
// before
const { agent } = await getAgentInfo({ rid, token }); // throws invalid-agent while queued
// after
const { room } = await getRoom(token);
if (!room?.servedBy) {
// still queued; retry when the room update announces the agent
await waitForAgentAssigned(rid);
}
const { agent } = await getAgentInfo({ rid, token }); Defensive patterns
Strategy: validation
Validate before calling
// Before agent.info, confirm the room actually has an agent assigned
const { room } = await getRoom(token); // livechat/room resolves by visitor token
if (!room?.servedBy?._id) {
// still queued: subscribe to room updates / retry later instead of calling agent.info
throw new PendingAssignmentError('agent not assigned yet');
}
const { agent } = await getAgentInfo(room._id, token); Type guard
function isServedRoom(room: unknown): room is { servedBy: { _id: string } } {
return typeof room === 'object' && room !== null &&
typeof (room as any).servedBy?._id === 'string';
} Try / catch
try { agent = await getAgentInfo(rid, token); } catch (e) { if (e.message === 'invalid-agent') { /* treat as pending assignment: retry with backoff until servedBy exists */ } else throw e; } Prevention
- Only call agent.info after the room announces an agent (agent-added callback).
- Treat invalid-agent as 'queued', not as a hard failure.
- Alert admins when servedBy points at a missing user so rooms get reassigned.
When it happens
Trigger: Calling livechat/agent.info right after creating the room, before RoutingManager assigns an agent (servedBy missing); calling it after the serving agent was deleted, deactivated, or removed from omnichannel while the room still references their id.
Common situations: Widget polling agent info in the gap between livechat/room creation and agent assignment (race); agent removed mid-conversation; stale room.servedBy pointing at a user deleted from the Users collection; testing on a fresh workspace where rooms sit in queue.
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
- agent-not-found
- error-forwarding-chat
- error-invalid-department-unit
- error-invalid-room
- error-invalid-user
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/6e058853d97ad052.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/server/api/v1/omnichannel/agent.ts:38
import { saveAgentInfo } from '../../../lib/omnichannel/omni-users';
import { setUserStatusLivechat, allowAgentChangeServiceStatus } from '../../../lib/omnichannel/utils';
import type { ExtractRoutesFromAPI } from '../../ApiClass';
API.v1.addRoute('livechat/agent.info/:rid/:token', {
async get() {
const visitor = await findGuest(this.urlParams.token);
if (!visitor) {
throw new Error('invalid-token');
}
const room = await findRoom(this.urlParams.token, this.urlParams.rid);
if (!room) {
throw new Error('invalid-room');
}
const agent = room?.servedBy && (await findAgent(room.servedBy._id));
if (!agent) {
throw new Error('invalid-agent');
}
return API.v1.success({ agent });
},
});
API.v1.addRoute(
'livechat/agent.next/:token',
{ validateParams: isGETAgentNextToken },
{
async get() {
const { token } = this.urlParams;
const room = await findOpenRoom(token, undefined, this.userId);
if (room) {
return API.v1.success();
}
let { department } = this.queryParams;View on GitHub (pinned to b2c16d5842)