Skip to content
Latchkey

NestJS ValidationPipe rejects request / metadata missing in CI

e2e tests fail with 400s because the global ValidationPipe rejected the payload. Either class-validator metadata is missing, or whitelist/forbidNonWhitelisted stripped or blocked fields the test sent.

What this error means

e2e requests that pass locally return "400 Bad Request" with a validation message array in CI, or every DTO passes with no validation because metadata was not emitted.

NestJS
{
  "statusCode": 400,
  "message": ["email must be an email", "property extra should not exist"],
  "error": "Bad Request"
}

Common causes

forbidNonWhitelisted blocks unexpected fields

With whitelist and forbidNonWhitelisted, any property not in the DTO triggers a 400, so a test payload with extra keys fails.

class-validator metadata is not available

Without emitted decorator metadata or the polyfill, validators do not attach, so validation either misbehaves or silently passes.

How to fix it

Align the pipe options with the payload

  1. Decide whether extra fields should be stripped (whitelist) or rejected (forbidNonWhitelisted).
  2. Make test payloads match the DTO exactly under strict settings.
  3. Enable transform so incoming plain objects become DTO instances.
main.ts
app.useGlobalPipes(new ValidationPipe({
  whitelist: true,
  forbidNonWhitelisted: true,
  transform: true,
}));

Ensure validator metadata is emitted

Keep emitDecoratorMetadata on and import reflect-metadata so class-validator decorators attach.

main.ts
import 'reflect-metadata';

How to prevent it

  • Configure the global ValidationPipe once and test payloads against it.
  • Keep decorator metadata enabled so validators attach.
  • Cover validation rules with tests so behavior changes are caught.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →