RocketChat/Rocket.Chat · error · Error

Invalid service URL

Error message

Invalid service URL

What it means

Thrown by POST livechat/triggers/:_id/external-service/call after the trigger passes the isExternalServiceTrigger guard, when trigger.actions[0].params has no serviceUrl (it is undefined or empty). The destructuring reads params.serviceUrl, so a saved action whose params object is missing serviceUrl, or where params itself is undefined, reaches this throw.

Source

Thrown at apps/meteor/ee/server/api/v1/omnichannel/triggers.ts:93

		async post() {
			const { _id: triggerId } = this.urlParams;
			const { token: visitorToken, extraData } = this.bodyParams;

			const trigger = await LivechatTrigger.findOneById(triggerId);

			if (!trigger) {
				throw new Error('Invalid trigger');
			}

			if (!trigger?.actions.length || !isExternalServiceTrigger(trigger)) {
				throw new Error('Trigger is not configured to use an external service');
			}

			const { params: { serviceTimeout = 5000, serviceUrl, serviceFallbackMessage = 'trigger-default-fallback-message' } = {} } =
				trigger.actions[0];

			if (!serviceUrl) {
				throw new Error('Invalid service URL');
			}

			const token = settings.get<string>('Livechat_secret_token');

			if (!token) {
				throw new Error('Livechat secret token is not configured');
			}

			const body = {
				metadata: extraData,
				visitorToken,
			};

			const headers = {
				'Accept': 'application/json',
				'Content-Type': 'application/json',
				'X-RocketChat-Livechat-Token': token,
			};

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Edit the trigger and fill in the service URL field under the 'Use an external service' action.
  2. Via the REST API, PATCH/recreate the trigger so actions[0].params.serviceUrl is a non-empty https URL.
  3. Validate the trigger document in mongo (db.livechat_trigger.findOne) to confirm params.serviceUrl is present before relying on the endpoint.
  4. If the URL was intentionally empty, switch the action to a different type instead of leaving it half-configured.

Example fix

// before - serviceUrl missing from params
{ "name": "use-external-service", "params": { "sender": "queue", "name": "bot" } }

// after
{ "name": "use-external-service", "params": { "sender": "queue", "name": "bot", "serviceUrl": "https://bot.example.com/inbox", "serviceTimeout": 5000, "serviceFallbackMessage": "fallback" } }
Defensive patterns

Strategy: validation

Validate before calling

function hasServiceUrl(trigger): boolean {
  return Boolean(trigger?.actions?.[0]?.params?.serviceUrl);
}

if (!hasServiceUrl(trigger)) {
  return showAdminConfigError('serviceUrl is missing on the external-service trigger');
}

Type guard

const isExternalServiceActionWithUrl = (
  action: unknown
): action is { name: 'use-external-service'; params: { serviceUrl: string } } =>
  typeof action === 'object' &&
  (action as any)?.name === 'use-external-service' &&
  typeof (action as any)?.params?.serviceUrl === 'string' &&
  (action as any).params.serviceUrl.length > 0;

Try / catch

try {
  await triggerExternalServiceCall(triggerId, visitorToken);
} catch (e) {
  if (e instanceof Error && e.message === 'Invalid service URL') {
    notifyAdminToConfigureServiceUrl(triggerId);
  }
}

Prevention

When it happens

Trigger: The trigger's action was created with name 'use-external-service' but its params object omitted serviceUrl (or left it as an empty string). The external-service/call endpoint then cannot form an outbound POST because no target URL exists.

Common situations: A trigger was partially configured through the UI (action type chosen, but the webhook URL field left blank), or created via API with a params object that lacks the serviceUrl key. Migration scripts that rebuilt trigger documents can also drop serviceUrl.

Related errors


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