RocketChat/Rocket.Chat · error · Error

apps-engine-not-loaded

Error message

apps-engine-not-loaded

What it means

Thrown by OutboundMessageProviderService.getProviderManager when Apps.self is not loaded (Apps.self?.isLoaded() returns falsy). The Apps Engine must finish loading before any outbound provider manager operation can run. Plain Error, code 'apps-engine-not-loaded'.

Source

Thrown at apps/meteor/ee/server/api/v1/omnichannel/lib/outbound.ts:48

		if (type !== undefined && !this.isProviderValid(type)) {
			throw new Error('Invalid type');
		}

		return this.provider.getOutboundMessageProviders(type);
	}

	public getProviderMetadata(providerId: string): Promise<IOutboundProviderMetadata> {
		const provider = this.provider.findOneByProviderId(providerId);
		if (!provider) {
			throw new Error('error-invalid-provider');
		}

		return this.getProviderManager().getProviderMetadata(provider.appId, provider.type);
	}

	private getProviderManager() {
		if (!Apps.self?.isLoaded()) {
			throw new Error('apps-engine-not-loaded');
		}

		const manager = Apps.self?.getManager()?.getOutboundCommunicationProviderManager();
		if (!manager) {
			throw new Error('apps-engine-not-configured-correctly');
		}

		return manager;
	}

	public sendMessage(providerId: string, message: IOutboundMessage) {
		const provider = this.provider.findOneByProviderId(providerId);
		if (!provider) {
			throw new Error('error-invalid-provider');
		}

		return this.getProviderManager().sendOutboundMessage(provider.appId, provider.type, message);
	}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Defer the outbound call until the Apps Engine reports loaded (listen for the apps-engine loaded event / Apps.self.isLoaded()).
  2. Check Apps.self?.isLoaded() before calling and queue/retry if false.
  3. Inspect server logs for Apps Engine load failures and resolve those first.
  4. Avoid invoking outbound operations from boot-time migrations.

Example fix

// before: call during boot
app.onServerStart(() => svc.getProviderMetadata(id));

// after: wait for the engine
if (!Apps.self?.isLoaded()) {
  await waitForAppsEngineLoaded();
}
svc.getProviderMetadata(id);
Defensive patterns

Strategy: retry

Validate before calling

// Probe Apps Engine load state before calling
import { Apps } from '@rocket.chat/apps';
function appsEngineReady(): boolean {
  return !!Apps.self?.isLoaded();
}
if (!appsEngineReady()) {
  // queue the call until loaded, or warn
  throw new Error('Apps Engine not loaded yet');
}

Type guard

function appsEngineLoaded(apps: typeof Apps): boolean {
  return !!apps.self?.isLoaded();
}

Try / catch

async function withAppsEngineReady<T>(fn: () => T | Promise<T>): Promise<T> {
  try {
    return await fn();
  } catch (e) {
    if (e.message === 'apps-engine-not-loaded') {
      await waitForAppsEngineLoaded();
      return fn();
  }
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling getProviderMetadata/sendMessage during server startup before the Apps Engine has finished initializing, or after the engine failed to load. Also reachable via code paths invoked very early in boot.

Common situations: Startup race: an omnichannel init hook or a deferred job fires before Apps Engine load completes; Apps Engine disabled or crashed during boot; calling from a migration that runs pre-engine.

Related errors


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