{"id":"0fdc74c4e522196a","repo":"nestjs/nest","slug":"validation-failed-0fdc74","errorCode":null,"errorMessage":"Validation failed","messagePattern":"Validation failed","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"sample/36-hmr-esm/src/common/pipes/validation.pipe.ts","lineNumber":21,"sourceCode":"  BadRequestException,\n  Injectable,\n  PipeTransform,\n  Type,\n} from '@nestjs/common';\nimport { plainToInstance } from 'class-transformer';\nimport { validate } from 'class-validator';\n\n@Injectable()\nexport class ValidationPipe implements PipeTransform<any> {\n  async transform(value: any, metadata: ArgumentMetadata) {\n    const { metatype } = metadata;\n    if (!metatype || !this.toValidate(metatype)) {\n      return value;\n    }\n    const object = plainToInstance(metatype, value);\n    const errors = await validate(object);\n    if (errors.length > 0) {\n      throw new BadRequestException('Validation failed');\n    }\n    return value;\n  }\n\n  private toValidate(metatype: Type<any>): boolean {\n    const types = [String, Boolean, Number, Array, Object];\n    return !types.find(type => metatype === type);\n  }\n}\n","sourceCodeStart":3,"sourceCodeEnd":31,"githubUrl":"https://github.com/nestjs/nest/blob/6ec0e2783d15290732447f304d8549b591b9749e/sample/36-hmr-esm/src/common/pipes/validation.pipe.ts#L3-L31","documentation":"A custom ValidationPipe (sample/36-hmr-esm/src/common/pipes/validation.pipe.ts) that runs class-transformer's plainToInstance then class-validator's validate against the handler's metatype (the DTO). At line 21 it throws BadRequestException('Validation failed') when any validation errors are produced. It is a stripped-down reimplementation of NestJS's global ValidationPipe, used by the HMR/ESM sample. The toValidate() guard skips JS primitives (String, Boolean, Number, Array, Object) so only DTO classes get validated.","triggerScenarios":"POST/PUT/MUTATION whose body violates the DTO's class-validator decorators: missing required @IsString/@IsInt fields, wrong primitive types, out-of-range numbers (@Min/@Max), or failing custom constraints.","commonSituations":"DTO class has NO decorators → validate returns [] and bad payloads slip through (the pipe silently passes); nested objects aren't validated because plainToInstance isn't recursive without transform options; the pipe isn't registered globally so some routes skip it; whitelist semantics differ from the built-in pipe.","solutions":["Add the missing class-validator decorators to the DTO (e.g., @IsString(), @IsInt(), @IsNotEmpty()).","Send a payload matching the DTO contract from the client.","Consider the built-in ValidationPipe with whitelist, forbidNonWhitelished, and transform enabled for stronger guarantees than the sample.","Expand the thrown error to include the validation errors array for actionable client feedback."],"exampleFix":"// before\nconst errors = await validate(object);\nif (errors.length > 0) {\n  throw new BadRequestException('Validation failed');\n}\n\n// after\nconst errors = await validate(object);\nif (errors.length > 0) {\n  throw new BadRequestException(\n    errors.map(e => Object.values(e.constraints ?? {}).join(', ')).join('; '),\n  );\n}","handlingStrategy":"validation","validationCode":"// Client-side guard before posting\nfunction looksLikeDto(v: unknown): v is MyDto {\n  return typeof v === 'object' && v !== null\n    && typeof (v as any).name === 'string'\n    && Number.isFinite((v as any).quantity);\n}\nif (!looksLikeDto(body)) throw new Error('payload does not match DTO');","typeGuard":"import { validateOrReject } from 'class-validator';\nimport { plainToInstance } from 'class-transformer';\n\nasync function isValidDto<T>(cls: new () => T, raw: unknown): Promise<boolean> {\n  try {\n    await validateOrReject(plainToInstance(cls, raw));\n    return true;\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  return await controller.handler(payload); // pipe runs\n} catch (e) {\n  if (e instanceof BadRequestException) {\n    return reply.code(400).send({ message: e.message, details: e.getResponse() });\n  }\n  throw e;\n}","preventionTips":["Put validation decorators (@IsString, @IsInt, etc.) on every DTO field.","Prefer the built-in global ValidationPipe with whitelist + forbidNonWhitelisted + transform.","Return the class-validator errors array in the message for actionable feedback.","Write a unit test per DTO that asserts invalid payloads are rejected."],"tags":["nestjs","validation","class-validator","http-400","hmr"],"analyzedSha":"6ec0e2783d15290732447f304d8549b591b9749e","analyzedAt":"2026-08-03T17:42:23.673Z","schemaVersion":2}