nestjs/nest · error · BadRequestException

Validation failed

Error message

Validation failed

What it means

A hand-rolled ParseIntPipe (sample/36-hmr-esm/src/common/pipes/parse-int.pipe.ts) that calls parseInt(value, 10) on an inbound route argument and throws BadRequestException('Validation failed') when the result is NaN. It is a minimal reimplementation of @nestjs/common's built-in ParseIntPipe, here to demonstrate the HMR/ESM sample's custom pipe plumbing. NaN happens when parseInt cannot find any leading digits (empty string, letters, symbols).

Source

Thrown at sample/36-hmr-esm/src/common/pipes/parse-int.pipe.ts:13

import {
  ArgumentMetadata,
  BadRequestException,
  Injectable,
  PipeTransform,
} from '@nestjs/common';

@Injectable()
export class ParseIntPipe implements PipeTransform<string> {
  async transform(value: string, metadata: ArgumentMetadata) {
    const val = parseInt(value, 10);
    if (isNaN(val)) {
      throw new BadRequestException('Validation failed');
    }
    return val;
  }
}

View on GitHub (pinned to 6ec0e2783d)

Solutions

  1. Send a valid integer in the parameter (fix the client URL/query).
  2. Prefer NestJS's built-in ParseIntPipe, which produces a clearer message, unless the sample specifically needs a custom one.
  3. Tighten the check to reject non-integer strings like '12px' that parseInt silently accepts: compare String(val) !== value.
  4. Return a more descriptive message instead of the bare 'Validation failed'.

Example fix

// before
const val = parseInt(value, 10);
if (isNaN(val)) {
  throw new BadRequestException('Validation failed');
}

// after
const val = Number(value);
if (!Number.isInteger(val)) {
  throw new BadRequestException(`Validation failed: "${value}" is not an integer`);
}
Defensive patterns

Strategy: validation

Validate before calling

// Client-side: only emit numeric segments.
function toIntParam(v: string | undefined): number {
  if (v == null || !/^-?\d+$/.test(v)) {
    throw new Error(`"${v}" is not an integer`);
  }
  return Number(v);
}

Type guard

function isIntegerString(v: unknown): v is string {
  return typeof v === 'string' && /^-?\d+$/.test(v);
}

Try / catch

// In an exception filter or controller layer
try {
  const id = parseIntPipe.transform(req.params.id, { type: 'param' });
} catch (e) {
  if (e instanceof BadRequestException) {
    return reply.code(400).send({ message: 'id must be an integer' });
  }
  throw e;
}

Prevention

When it happens

Trigger: A request whose piped parameter is not a valid integer: e.g., GET /items/abc where 'abc' flows through ParseIntPipe, or ?page= (empty). parseInt('abc',10) and parseInt('',10) both yield NaN → 400.

Common situations: Route registered without the pipe so a non-numeric segment reaches the handler; legacy/SEO URLs with slug-style ids hitting a numeric route; empty query params not stripped; client sending floating or padded strings the pipe rejects.

Related errors


AI-assisted analysis of nestjs/nest@6ec0e2783d (2026-08-03). Data as JSON: /data/errors/0933f1f5a9cad040.json. Report an issue: GitHub.