Skip to content

circular dependency detected using swagger annotation with swc #3326

@andreasvh-conceto

Description

@andreasvh-conceto

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

Whenever using swagger annotations like @ApiProperty() or @ApiPropertyOptional on an constified version of an enum in combination with swc builder, it throws a circular dependency error:

import { ApiPropertyOptional } from '@nestjs/swagger';

export const MyEnum = {
  FOO: 'FOO',
  BAR: 'BAR',
} as const;
export type MyEnum = (typeof MyEnum)[keyof typeof MyEnum];

export class MyDto {
  @ApiPropertyOptional() // will result in circular dependency issue, same for @ApiProperty
  @IsOptional()
  someEnum?: MyEnum;
}

After building with swc and starting the application and when accessing the swagger api it crashes with a circular dependency error. The error message does not hold enough information . I configured a project which will provoke this error in the steps to reproduce section. Here is the full error message:

[Nest] 69440 - 03/01/2025, 3:12:31 PM ERROR [ExceptionsHandler] Error: A circular dependency has been detected (property key: "FOO"). Please, make sure that each side of a bidirectional relationships are using lazy resolvers ("type: () => ClassType").
at SchemaObjectFactory.createNotBuiltInTypeReference (/Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:258:19)
at SchemaObjectFactory.createSchemaMetadata (/Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:375:25)
at SchemaObjectFactory.mergePropertyWithMetadata (/Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:186:21)
at /Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:317:43
at Array.forEach ()
at SchemaObjectFactory.createFromObjectLiteral (/Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:301:24)
at SchemaObjectFactory.createSchemaMetadata (/Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:350:50)
at SchemaObjectFactory.mergePropertyWithMetadata (/Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:186:21)
at /Users/andreas.vanhelden/dev/nestjs-swagger-circular-dependency/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:115:35

Current workaround(s) are:

  1. Use different names for the enum Type and the type itself:
import { ApiPropertyOptional } from '@nestjs/swagger';
// Here MyEnum is the const itself and the same name is also used for the type
export const MyEnum2 = {
  FOO: 'FOO',
  BAR: 'BAR',
} as const;
export type MyEnum2Type = (typeof MyEnum2)[keyof typeof MyEnum2];
export class MyDto {
  @ApiPropertyOptional()
  @IsOptional()
  someEnum?: MyEnum2Type;
}
  1. Define the enum explicitly in the ApiPropertyOptional Annotation parameter:
import { ApiPropertyOptional } from '@nestjs/swagger';
// Here MyEnum is the const itself and the same name is also used for the type
export const MyEnum = {
  FOO: 'FOO',
  BAR: 'BAR',
} as const;
export type MyEnum = (typeof MyEnum)[keyof typeof MyEnum];
export class MyDto {
  @ApiPropertyOptional({ enum: MyEnum ) // or @ApiPropertyOptional({ enum: () => MyEnum })
  @IsOptional()
  someEnum?: MyEnum;
}

This issue was really hard to detect and it occured only after building and starting the application. There is just a small hint to the enum like ...Error: A circular dependency has been detected (property key: "FOO")...

It is also dangerous since this error only occurs after deploying and starting the application. On our side it was identified after the deployment on qa environment failed.

Minimum reproduction code

https://github.com/andreasvh-conceto/nestjs-swagger-circular-dependency

Steps to reproduce

  1. git clone git@github.com:andreasvh-conceto/nestjs-swagger-circular-dependency.git
  2. cd nestjs-swagger-circular-dependency
  3. npm i
  4. Go to the terminal and do npm run test:e2e
  5. Scroll up the failing app.e2e-spec.ts look at the circular dependency error.

Expected behavior

Here are several alternatives i would expect (from my favorite solution to the one i would i would at least expect):

  1. Swagger will somehow resolve that on its own. The error does not occur anymore if swagger Annotations are correctly used.
  2. The error occurs at development time, not after building the project with swc or can be at least easily been tested. The error message is improved and is giving more hints like mentioning the related Dto File, the concrete enum.
  3. The error message is improved and is giving more hints like mentioning the related Dto File and the concrete enum.

Currently we wrote an own test like in the steps to reproduce section, which will verify if Swagger could correctly load the Open Api spec. Maybe there are better ways.

Thanks!

Package version

11.0.5

NestJS version

11.0.1

Node.js version

v20.18.0

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

Only occurs building with swc and using swagger.

Metadata

Metadata

Assignees

No one assigned

    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