RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-token

error-invalid-token

Error message

Token cannot be empty

What it means

Thrown as Meteor.Error('error-invalid-token', 'Token cannot be empty') in POST livechat/visitor when bodyParams.visitor.token is missing, empty, or whitespace-only after trim. The route is unauthenticated (visitor-facing), so the token is the only identity anchor and must be non-empty.

Source

Thrown at apps/meteor/server/api/v1/omnichannel/visitor.ts:47

					name: Match.Maybe(String),
					email: Match.Maybe(String),
					department: Match.Maybe(String),
					phone: Match.Maybe(String),
					username: Match.Maybe(String),
					customFields: Match.Maybe([
						Match.ObjectIncluding({
							key: String,
							value: String,
							overwrite: Boolean,
						}),
					]),
				}),
			});

			const { customFields, id, token, name, email, department, phone, username, connectionData } = this.bodyParams.visitor;

			if (!token?.trim()) {
				throw new Meteor.Error('error-invalid-token', 'Token cannot be empty', { method: 'livechat/visitor' });
			}

			const guest = {
				token,
				...(id && { id }),
				...(name && { name }),
				...(email && { email }),
				...(department && { department }),
				...(username && { username }),
				...(connectionData && { connectionData }),
				...(phone && typeof phone === 'string' && { phone: { number: phone as string } }),
				connectionData: normalizeHttpHeaderData(this.request.headers),
			};

			const visitor = await registerGuest(guest, {
				shouldConsiderIdleAgent: settings.get<boolean>('Livechat_enabled_when_agent_idle'),
				shouldConsiderOfflineAgent: settings.get<boolean>('Livechat_accept_chats_with_no_agents'),
			});

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Generate a visitor token (UUID/v4 is typical) before calling the endpoint.
  2. Trim and assert non-empty client-side: if (!visitor.token?.trim()) return;
  3. Ensure the widget's token bootstrap runs before any registerVisitor network call.

Example fix

// before
await POST('/api/v1/livechat/visitor', { body: { visitor: { name, email } } });

// after
const token = visitor.token || crypto.randomUUID();
await POST('/api/v1/livechat/visitor', { body: { visitor: { token, name, email } } });
Defensive patterns

Strategy: validation

Validate before calling

const token = (body.visitor?.token ?? '').trim();
if (!token) throw new Error('visitor.token required');
await fetch('/api/v1/v1/livechat/visitor', { method:'POST', body: JSON.stringify({ visitor: { ...body.visitor, token } }) });

Type guard

function hasNonEmptyToken(v: { token?: string } | undefined): v is { token: string } {
  return !!v?.token?.trim();
}

Try / catch

null

Prevention

When it happens

Trigger: POST /api/v1/v1/livechat/visitor with visitor omitted, with visitor.token = '' or ' ', or with token = null. The preceding check() validates the body shape but token is not constrained to a non-empty String there.

Common situations: Livechat widget initializing before generating a visitor token; SDK call that forgets to set token; token cleared by an upstream sanitizer.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/b0c1a6c810845978. Report an issue: GitHub.