Fix Error: Cannot determine a type for the "CreateOrderDto.items" property. Make sure you've added the appropriate decorators. in NestJS
This error means NestJS Swagger cannot infer the type metadata for a DTO property because it lacks the required decorators. TypeScript metadata reflection does not preserve generic types like arrays. Fix it by adding @ApiProperty() with the type option and @Type() decorator from class-transformer.
Reading the Stack Trace
Here's what each line means:
- at SchemaObjectFactory.getTypeForArrayProperty (node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:182:19): The Swagger schema factory could not determine the array item type because generic type information is lost at runtime.
- at SwaggerExplorer.exploreRouteModel (node_modules/@nestjs/swagger/dist/swagger-explorer.js:218:33): While exploring route models to build the OpenAPI spec, the explorer encountered a property without type metadata.
- at bootstrap (src/main.ts:18:28): The error occurs during app bootstrap when SwaggerModule.createDocument() scans all DTOs.
Common Causes
1. Array property without @ApiProperty type
A DTO has an array property but @ApiProperty does not specify the type of the array items.
export class CreateOrderDto {
@IsArray()
items: OrderItemDto[]; // Swagger can't infer OrderItemDto from reflection
}
2. Missing emitDecoratorMetadata in tsconfig
TypeScript is not configured to emit decorator metadata, so NestJS cannot read type information at runtime.
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true
// Missing: "emitDecoratorMetadata": true
}
}
3. Generic type not expressible via metadata
TypeScript's reflect-metadata cannot represent generic types like Map<string, number> or Record<string, any>.
export class ConfigDto {
@ApiProperty()
settings: Record<string, any>; // Type erased to Object at runtime
}
The Fix
Add @ApiProperty({ type: [OrderItemDto] }) to explicitly tell Swagger the array item type. Add @Type(() => OrderItemDto) from class-transformer so validation pipes can properly instantiate nested objects.
import { IsArray, IsNumber, IsString, ValidateNested } from 'class-validator';
export class OrderItemDto {
@IsString()
productId: string;
@IsNumber()
quantity: number;
}
export class CreateOrderDto {
@IsArray()
@ValidateNested({ each: true })
items: OrderItemDto[];
}
import { IsArray, IsNumber, IsString, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiProperty } from '@nestjs/swagger';
export class OrderItemDto {
@ApiProperty({ example: 'prod-123' })
@IsString()
productId: string;
@ApiProperty({ example: 2 })
@IsNumber()
quantity: number;
}
export class CreateOrderDto {
@ApiProperty({ type: [OrderItemDto] })
@IsArray()
@ValidateNested({ each: true })
@Type(() => OrderItemDto)
items: OrderItemDto[];
}
Testing the Fix
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';
import { CreateOrderDto, OrderItemDto } from './create-order.dto';
describe('CreateOrderDto', () => {
it('validates a correct order', async () => {
const dto = plainToInstance(CreateOrderDto, {
items: [{ productId: 'prod-1', quantity: 2 }],
});
const errors = await validate(dto);
expect(errors).toHaveLength(0);
});
it('rejects missing items', async () => {
const dto = plainToInstance(CreateOrderDto, {});
const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
});
it('rejects invalid nested items', async () => {
const dto = plainToInstance(CreateOrderDto, {
items: [{ productId: 123, quantity: 'abc' }],
});
const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
});
});
Run your tests:
npm test
Pushing Through CI/CD
git checkout -b fix/nestjs-swagger-schema-error,git add src/order/dto/create-order.dto.ts src/order/dto/__tests__/create-order.dto.spec.ts,git commit -m "fix: add ApiProperty and Type decorators for Swagger schema generation",git push origin fix/nestjs-swagger-schema-error
Your CI config should look something like this:
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
- run: npm run build
The Full Manual Process: 18 Steps
Here's every step you just went through to fix this one bug:
- Notice the error alert or see it in your monitoring tool
- Open the error dashboard and read the stack trace
- Identify the file and line number from the stack trace
- Open your IDE and navigate to the file
- Read the surrounding code to understand context
- Reproduce the error locally
- Identify the root cause
- Write the fix
- Run the test suite locally
- Fix any failing tests
- Write new tests covering the edge case
- Run the full test suite again
- Create a new git branch
- Commit and push your changes
- Open a pull request
- Wait for code review
- Merge and deploy to production
- Monitor production to confirm the error is resolved
Total time: 30-60 minutes. For one bug.
Or Let bugstack Fix It in Under 2 minutes
Every step above? bugstack does it automatically.
Step 1: Install the SDK
npm install bugstack-sdk
Step 2: Initialize
import { initBugStack } from 'bugstack-sdk'
initBugStack({ apiKey: process.env.BUGSTACK_API_KEY })
Step 3: There is no step 3.
bugstack handles everything from here:
- Captures the stack trace and request context
- Pulls the relevant source files from your GitHub repo
- Analyzes the error and understands the code context
- Generates a minimal, verified fix
- Runs your existing test suite
- Pushes through your CI/CD pipeline
- Deploys to production (or opens a PR for review)
Time from error to fix deployed: Under 2 minutes.
Human involvement: zero.
Try bugstack Free →No credit card. 5-minute setup. Cancel anytime.
Deploying the Fix (Manual Path)
- Add @ApiProperty with explicit type for array and nested properties.
- Add @Type() decorator for nested object validation.
- Verify emitDecoratorMetadata is true in tsconfig.json.
- Run tests and verify swagger.json generates correctly.
- Open a PR, merge after CI, and check Swagger UI in staging.
Frequently Asked Questions
BugStack runs the fix through your existing test suite, generates additional edge-case tests, and validates that no other modules are affected before marking it safe to deploy.
BugStack never pushes directly to production. Every fix goes through a pull request with full CI checks, so your team can review it before merging.
If you enable the Swagger CLI plugin in nest-cli.json, it can auto-infer simple types. But arrays, nested objects, and generics always need explicit @ApiProperty with the type option.
Use @ApiProperty({ required: false }) or @ApiPropertyOptional(). Combine with @IsOptional() from class-validator for validation.