nestjs/nest · error · Error

"on" method not supported by the underlying server

Error message

"on" method not supported by the underlying server

What it means

Thrown by NestMicroservice.on() when the underlying serverInstance does not have an 'on' method (the runtime checks "on" in this.serverInstance). The hybrid NestMicroservice wrapper exposes on()/unwrap() generically, but delegates to the concrete server; if that server's transport does not implement event subscription (notably ServerGrpc.on() throws its own 'not supported in gRPC mode' message, and custom servers may omit on()), the wrapper falls through to this generic rejection.

Source

Thrown at packages/microservices/nest-microservice.ts:334

  /**
   * Sets the flag indicating that the init hook was called.
   * @param isInitHookCalled Value to set
   */
  public setIsInitHookCalled(isInitHookCalled: boolean) {
    this.wasInitHookCalled = isInitHookCalled;
  }

  /**
   * Registers an event listener for the given event.
   * @param event Event name
   * @param callback Callback to be executed when the event is emitted
   */
  public on(event: string | number | symbol, callback: Function) {
    if ('on' in this.serverInstance) {
      return this.serverInstance.on(event as string, callback);
    }
    throw new Error('"on" method not supported by the underlying server');
  }

  /**
   * Returns an instance of the underlying server/broker instance,
   * or a group of servers if there are more than one.
   */
  public unwrap<T>(): T {
    if ('unwrap' in this.serverInstance) {
      return this.serverInstance.unwrap();
    }
    throw new Error('"unwrap" method not supported by the underlying server');
  }

  protected async closeApplication(): Promise<any> {
    this.socketModule && (await this.socketModule.close());
    this.microservicesModule && (await this.microservicesModule.close());

    await super.close();

View on GitHub (pinned to 6ec0e2783d)

Solutions

  1. For status, use the per-transport status Observable on the server/client instead of microservice.on().
  2. If you need on(), use a transport whose Server implements it (TCP/Redis/RMQ/MQTT/NATS) or add an on() method to your custom Server subclass.
  3. Avoid calling on() on a gRPC-backed NestMicroservice — gRPC events are surfaced differently.

Example fix

// before
const app = await NestFactory.createMicroservice(AppModule, { transport: Transport.GRPC, options: {...} });
app.on('connection', fn); // throws

// after
// gRPC does not support on(); use client.status / gRPC interceptors for lifecycle hooks
// or switch transport if you need this API
Defensive patterns

Strategy: type-guard

Validate before calling

function supportsOn(server: any): boolean {
  return server && 'on' in server && typeof server.on === 'function'
    && !/GRPC/.test(server.constructor?.name);
}
if (supportsOn(server)) server.on(event, cb);
else { /* use status Observable or transport-specific hook */ }

Type guard

import { ServerGrpc } from '@nestjs/microservices';
const supportsServerOn = (s: any): boolean => !(s instanceof ServerGrpc) && 'on' in s;

Try / catch

try {
  app.on(event, cb);
} catch (e) {
  if (/"on" method not supported/.test(e?.message)) { /* use status / transport-specific API */ }
  else throw e;
}

Prevention

When it happens

Trigger: Calling app.on(event, cb) (or microservice.on(...)) on a NestMicroservice whose server is a gRPC server or a custom Server subclass that does not define on(). Generic lifecycle code that attaches listeners to whatever microservice is running.

Common situations: Mixing gRPC into a hybrid app and trying to subscribe to server events via the microservice handle. A custom Server implementation without on(). Code written for TCP/Redis servers that assumes every server supports on().

Related errors


AI-assisted analysis of nestjs/nest@6ec0e2783d (2026-08-03). Data as JSON: /data/errors/7a8d42b9825951cd.json. Report an issue: GitHub.