nestjs/nest · warning · NotFoundException

Cannot ${method} ${url}

Error message

Cannot ${method} ${url}

What it means

This is the framework's built-in not-found handler: after route registration NestJS installs a catch-all callback that throws `NotFoundException('Cannot <method> <url>')` for any request no route matched, producing the standard 404 body. Seeing it means the router had no matching handler — which may be perfectly correct behavior, or a symptom that your routes/prefix/versioning are not registered the way you think.

Source

Thrown at packages/core/router/routes-resolver.ts:160

        };
        this.routerExplorer.explore(
          instanceWrapper,
          moduleName,
          applicationRef,
          host!,
          routePathMetadata,
          options,
        );
      });
    });
  }

  public registerNotFoundHandler() {
    const applicationRef = this.container.getHttpAdapterRef();
    const callback = <TRequest, TResponse>(req: TRequest, res: TResponse) => {
      const method = applicationRef.getRequestMethod(req);
      const url = applicationRef.getRequestUrl(req);
      throw new NotFoundException(`Cannot ${method} ${url}`);
    };
    const handler = this.routerExceptionsFilter.create({}, callback, undefined);
    const proxy = this.routerProxy.createProxy(callback, handler);
    const prefix = this.applicationConfig.getGlobalPrefix();
    applicationRef.setNotFoundHandler &&
      applicationRef.setNotFoundHandler(proxy, prefix);
  }

  public registerExceptionHandler() {
    const callback = <TError, TRequest, TResponse>(
      err: TError,
      req: TRequest,
      res: TResponse,
      next: Function,
    ) => {
      throw this.container.getHttpAdapterRef().mapException(err);
    };
    const handler = this.routerExceptionsFilter.create(

View on GitHub (pinned to dd75d7bd8c)

Solutions

  1. Compare the exact URL and method against your registered routes (log them from the router or check the OpenAPI/Explorer output).
  2. Account for `setGlobalPrefix` and versioning in the URL you call.
  3. Make sure the controller class is declared in the module's `controllers` array and the module is imported.
  4. If the 404 is expected, keep it — or replace the default handler/exception mapping with a custom one for a better payload.

Example fix

// before: client calls /users but app uses prefix
await app.setGlobalPrefix('api');
// GET /users -> Cannot GET /users

// after
// GET /api/users -> 200
// or drop the prefix if the contract requires /users
Defensive patterns

Strategy: fallback

Try / catch

// Map the default 404 to a useful payload for API consumers
import { Catch, NotFoundException, ExceptionFilter, ArgumentsHost } from '@nestjs/common';

@Catch(NotFoundException)
export class NotFoundFilter implements ExceptionFilter {
  catch(_: NotFoundException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    ctx.getResponse().status(404).json({
      statusCode: 404,
      error: 'Not Found',
      hint: 'Check the global prefix and route versioning (e.g. /api/v1/...)',
    });
  }
}

Prevention

When it happens

Trigger: Requesting a misspelled or missing path; a global prefix (set via `app.setGlobalPrefix('api')`) that the caller omitted or doubled; URI versioning enabled so the real path is `/v1/users` while `/users` 404s; the controller not being listed in its module's `controllers`; route params mismatching (e.g., `@Get('users/:id')` but requesting `/users/1/orders`) so the more specific path 404s.

Common situations: Frontend hardcoded paths drifting from backend routes after adding a global prefix; API consumers forgetting the version segment; proxy/gateway stripping or adding path prefixes; controllers forgotten in modules after refactors; HTTP method confusion (POST-only route hit with GET yields 404, not 405, since no route matches).

Related errors


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