nestjs/nest · critical · UnknownRequestMappingException

An invalid controller has been detected. "${className}" does

Error message

An invalid controller has been detected. "${className}" does not have the @Controller() decorator but it is being listed in the "controllers" array of some module.

What it means

While mapping controllers to routes the framework reads the path metadata that the `@Controller()` decorator writes onto the class. A class listed in a module's `controllers` array without that decorator has no PATH_METADATA, so NestJS throws UnknownRequestMappingException — 'An invalid controller has been detected. X does not have the @Controller() decorator but it is being listed in the controllers array of some module.'

Source

Thrown at packages/core/router/router-explorer.ts:131

  ) {
    const { instance } = instanceWrapper;
    const routerPaths = this.pathsExplorer.scanForPaths(instance);
    this.applyPathsToRouterProxy(
      httpAdapterRef,
      routerPaths,
      instanceWrapper,
      moduleKey,
      routePathMetadata,
      host,
      options,
    );
  }

  public extractRouterPath(metatype: Type<Controller>): string[] {
    const path = Reflect.getMetadata(PATH_METADATA, metatype);

    if (isUndefined(path)) {
      throw new UnknownRequestMappingException(metatype);
    }
    if (Array.isArray(path)) {
      return path.map(p => addLeadingSlash(p));
    }
    return [addLeadingSlash(path)];
  }

  public applyPathsToRouterProxy<T extends HttpServer>(
    router: T,
    routeDefinitions: RouteDefinition[],
    instanceWrapper: InstanceWrapper,
    moduleKey: string,
    routePathMetadata: RoutePathMetadata,
    host: string | RegExp | Array<string | RegExp>,
    options: RouteResolutionOptions = {},
  ) {
    (routeDefinitions || []).forEach(routeDefinition => {
      const { version: methodVersion } = routeDefinition;

View on GitHub (pinned to dd75d7bd8c)

Solutions

  1. Decorate the class: `@Controller('path')` on the exact class listed in the module.
  2. If the class is not meant to handle HTTP, move it to `providers` instead.
  3. Ensure the correct class is imported (check for default vs named import mismatches) and the decorator is applied to the class, not exported separately.
  4. Verify tsconfig: `experimentalDecorators: true` and, for emitted metadata, `emitDecoratorMetadata: true`.

Example fix

// before
export class CatsController { // decorator missing
  @Get() findAll() { return []; }
}

// after
import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get() findAll() { return []; }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Wiring test: every class in controllers arrays must carry controller metadata
import { CONTROLLER_WATERMARK, PATH_METADATA } from '@nestjs/common/constants';
import 'reflect-metadata';

const isNestController = (cls: any): boolean =>
  typeof cls === 'function' &&
  !!Reflect.getMetadata(CONTROLLER_WATERMARK, cls) &&
  Reflect.getMetadata(PATH_METADATA, cls) !== undefined;

function assertControllersValid(module: Function) {
  for (const c of Reflect.getMetadata('controllers', module) ?? []) {
    if (!isNestController(c)) throw new Error(`${module.name}: ${c?.name} is not decorated with @Controller()`);
  }
}

Type guard

const isNestController = (cls: unknown): cls is import('@nestjs/common').Type<any> =>
  typeof cls === 'function' && Reflect.getMetadata('__controller__', cls) !== undefined;

Prevention

When it happens

Trigger: A plain class (service, DTO, utility) mistakenly added to a module's `controllers` array; the decorator was deleted or commented out during refactoring; the class is decorated by a custom pseudo-decorator that does not apply @Controller(); copy-paste of a controller file where the decorator line was not copied; decorators disabled in tsconfig (`experimentalDecorators: false`) so nothing gets written.

Common situations: Renaming a controller into a service but leaving it registered under controllers; large modules where arrays get long; upgrades to build tooling (swc/esbuild configs) that silently drop decorators when misconfigured; scaffolding mistakes.

Related errors


AI-assisted analysis of nestjs/nest@dd75d7bd8c (2026-08-21). Data as JSON: /api/errors/6de80ed0853e0519. Report an issue: GitHub.