medusajs/medusa · warning

No emitEvents_ method found on ${target.constructor.name}. N

Error message

No emitEvents_ method found on ${target.constructor.name}. No events emitted. To be able to use the @EmitEvents() you need to have the emitEvents_ method implemented in the class.

What it means

The @EmitEvents() decorator runs the decorated method, then forwards the aggregated messages collected via the MedusaContext messageAggregator to the class's emitEvents_ method. If the service class has no emitEvents_ method, the collected events are simply dropped with this warning. The method is normally provided by extending MedusaService; hand-written services that add the decorator without the base class lose events.

Source

Thrown at packages/core/utils/src/modules-sdk/decorators/emit-events.ts:32

  return function (
    target: any,
    propertyKey: string | symbol,
    descriptor: any
  ): void {
    InjectIntoContext({
      messageAggregator: () => new MessageAggregator(),
    })(target, propertyKey, descriptor)

    const original = descriptor.value

    descriptor.value = async function (...args: any[]) {
      const result = await original.apply(this, args)

      if (!target.emitEvents_) {
        const logger = Object.keys(this.__container__ ?? {}).includes("logger")
          ? this.__container__.logger
          : console
        logger.warn(
          `No emitEvents_ method found on ${target.constructor.name}. No events emitted. To be able to use the @EmitEvents() you need to have the emitEvents_ method implemented in the class.`
        )
      }

      const argIndex = target.MedusaContextIndex_[propertyKey]
      const aggregator = args[argIndex].messageAggregator as MessageAggregator

      if (aggregator.count() > 0) {
        await target.emitEvents_.apply(this, [aggregator.getMessages(options)])
        aggregator.clearMessages()
      }

      return result
    }
  }
}

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Make the class extend MedusaService<...>(models), which implements emitEvents_
  2. Or implement emitEvents_ manually: protected async emitEvents_(context: Context) { ... flush context.messageAggregator messages ... }
  3. Remove @EmitEvents() from methods of classes that should not emit domain events

Example fix

// before
export class MyService { // no base class
  @EmitEvents()
  async createThing(...) {}
}

// after
export class MyService extends MedusaService<{ Thing: { dto: ThingDTO } }>({ Thing }) {
  @EmitEvents()
  async createThing(...) {}
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof (service as any).emitEvents_ !== "function") {
  console.warn("@EmitEvents used on class without emitEvents_")
}

Type guard

const canEmitEvents = (s: object): boolean =>
  typeof (s as { emitEvents_?: unknown }).emitEvents_ === "function"

Prevention

When it happens

Trigger: Adding @EmitEvents() to a method of a class that does not extend MedusaService (or otherwise does not define an async emitEvents_(context) method). Medusa module services like ApiKeyModuleService/CartModuleService etc. get it from the base class, so this only fires for custom or mis-wired classes.

Common situations: Building a custom service that mimics Medusa module services and copying the decorator; refactoring a service to no longer extend MedusaService while keeping decorators; mocking services in tests (FakeService) that apply the decorator without the base implementation.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/eebabc3e3fd3b9a0. Report an issue: GitHub.