Skip to content

Regression in 11.2.7: plugin drops auto-inferred 2xx response when only error @Api*Response decorators are present (PR #3803) #3862

@PeterTheOne

Description

@PeterTheOne

Did you read the migration guide?

  • I have read the whole migration guide

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Potential Commit/PR that introduced the regression

PR #3803 (released in 11.2.7)

Versions

11.2.6 → 11.2.7 (regression still present in 11.3.2)

Describe the regression

PR #3803 (fixes #1639) added a hasExplicitApiResponseDecorator check that suppresses the auto-inferred default response when any decorator whose name matches Api*Response is present. The check doesn't distinguish success (2xx) from error (4xx/5xx) status codes — so a handler decorated with only @ApiUnauthorizedResponse() (or @ApiNotFoundResponse(), @ApiForbiddenResponse(), etc.) no longer gets the auto-inferred 201/200 response in the OpenAPI spec.

The resulting spec lists only the error status code. Downstream client generators (NSwag, openapi-generator, etc.) can't tell that a 2xx is legitimate and treat the real 2xx response as an exception at runtime.

Before 11.2.7, the default 201/200 was always appended, so these handlers produced a complete spec even without an explicit success decorator.

Minimum reproduction code

import { Controller, Post } from '@nestjs/common';
import { ApiUnauthorizedResponse } from '@nestjs/swagger';

@Controller('session')
export class SessionController {
  @Post('start')
  @ApiUnauthorizedResponse()
  startSession(): void {
    // defaults to 201 Created at runtime
  }
}

Resulting OpenAPI spec:

# 11.2.6 (correct)
/session/start:
  post:
    responses:
      '201': { description: '' }       # ← auto-inferred, correct
      '401': { description: '' }

# 11.2.7+ (broken)
/session/start:
  post:
    responses:
      '401': { description: '' }       # ← 201 silently dropped

Expected behavior

The auto-inferred 2xx response should only be suppressed when at least one success @Api*Response decorator (2xx) is already declared on the handler. Error-only decorators (@ApiUnauthorizedResponse, @ApiNotFoundResponse, @ApiForbiddenResponse, @ApiBadRequestResponse, @ApiConflictResponse, etc.) should not suppress the default.

Other

Real-world impact: in our codebase, a POST /portal-session/start handler with just @ApiUnauthorizedResponse() started throwing ApiException on every successful login after we bumped to 11.2.7, because the generated Angular client had no entry for 201 in its response handler. Downgrading to 11.2.6 confirmed the regression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions