class-validator: Deep nested validation broken

Description

When trying to validate nested objects using @ValidateNested(), whitelist: true and forbidNonWhitelisted: true, error "property XY should not exist" gets thrown for no apparent reason.

Reproduction

Here a vastly simplified version of my use case:

class ProductPricing {
    @Type(() => ProductPricingOptionsDTO)
    options: ProductPricingOptionsDTO;
}
class ProductPricingOptionsDTO{
    @ValidateNested()
    @Type(() => OnlineUserPricingOptionsDTO)
    onlineUserPrices: OnlineUserPricingOptionsDTO;
}
class OnlineUserPricingOptionsDTO{
    @IsNumber()
    @Min(2)
    price: number;
}

and validating the following payload:

{
    "options": {
        "onlineUserPrices": {
            "price": 2
        }
    }
}

with whitelist: true, forbidNonWhitelisted: true throws an error containing the following message:

"constraints": {
    "whitelistValidation": "property price should not exist"            }
}

Environment

  • nodejs:
  • browser:
  • typeorm:

class-validator version: ^0.12.1

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 7
  • Comments: 26 (1 by maintainers)

Most upvoted comments

Cheers! We have found out that adding @Type(() => NestedType) was the thing. It works without adding that parameter which you suggested. Adding comment for “future generations”.

Hi! I had the same issue but I managed to resolve it by using:

transformOptions: {
    enableImplicitConversion: true,
},

Please let me know if it helped also in your cases.

Setting only forbidNonWhitelisted: true is necessary to reproduce this problem, that will throw the property X should not exist message

For setting only forbidUnknownValues: true, the class-validator will throw with an unknown value was passed to the validate

If both options are enabled, it will give an error in the first check rule

For example: If my PipeValidation is

new ValidationPipe({
   whitelist: true,
   forbidUnknownValues: true,
   forbidNonWhitelisted: true,
})

It will throw the forbidUnknownValues message because it’s the first rule checked at ValidationPipe, the same occurs if forbidNonWhitelisted is above forbidUnknown but it will throw property X should not exist message instead

I also encountered this issue when using the plainToClass() class transformer. I tried to reproduce this issue in this CodeSandbox. While doing so I noticed that plainToClass() doesn’t convert nested “class” objects to the desired class, what actually shouldn’t be an issue if you’re not strictly validating the type of the nested object (like in my example).

As you might have seen my example includes some tests what, I think, cover all cases regarding this issue and if you run them you will see that they all pass. Which is strange because when running the server, defined in index.ts, you can see that it does give an error. The server runs a validation for data with and without class transformer and while doing so the whitelist and forbidNonWhitelisted flag are set to true, resulting in errors for the validation with class transformer. This is the only way I could manage to make the validator return validation errors.

To summarize I think that this issue can be solved by making the whitelist function declared here recursive, for objects and arrays of objects.

Ok. Update on my case. @Type decorator didn’t work as should when used yarn link along with class-transformer in peerDependency. So option enableImplicitConversion: true helped me because of not working @Type but when not linked everything works as it should 👍 .

I had property xxx should not exist with whitelist rule set to true error but my problem was that I wasn’t specifying any decorators for nested properties, whereas in the docs they write:

(validate)… will strip all properties that don’t have any decorators. If no other decorator is suitable for your property, you can use @Allow decorator

Now everything works fine with @ValidateNested

@MickL are you sure it is not still broken? Have you tried to validate objects that are nested more than 2 levels deep? That is the issue i was running into. It works on second level objects but fails for 3rd level or deeper. Even when adding @Type(() => MyClass)

I don’t think this issue should be closed until it is confirmed the validation works on 3rd level objects.

I am pretty sure this issue can be closed because nested validation is NOT broken:

When using @ValidateNested() from class-validator then the property needs to be an instance of the desired class not a plain object. If you use class-transformer then it will not automatically transform your nested objects into classes. Instead you need to add the decorator @Type(() => MyClass) so class-transformer will transform your nested objects into instances of the class and THEN @ValidateNested() from class-validator will work as expected.

If you activate enableImplicitConversion then class-validator will do this transformation for you, but as the documentation states you should not enable enableImplicitConversion when using class-transformer.

@hood May you verify and close this issue?

@murbanowicz adding @Type(() => NestedType) seems to only be working on second level objects. If you go down one more level like in the OP validation doesn’t work on the third level object. I will try @gabrieloczkowski suggestion for enableImplicitConversion: true today and see if it works.