express-validator
semver
>=6.0.0 <8.0.0postconditions31functions15last verified2026-06-24coverage score93%Postconditions: what we check
- validationResult · errors-not-checkederrorWhenvalidationResult() is called but the result is not inspected before using request dataReturnsValidation errors exist but are silently ignored. Invalid input is processed as if valid.Required handlingCaller MUST call validationResult(req) and check isEmpty() or the errors array before using validated fields. Failing to check means invalid input silently passes through. Pattern: const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- validationResult · success-no-errorsinfoWhenAll validation chains passed for the requestReturnsResult object with isEmpty() === trueRequired handlingNo action required — use the returned value as needed.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2]
- validationResult · validation-failedinfoWhenOne or more validation chains failed for the requestReturnsResult object with isEmpty() === false. errors.array() returns list of {type, msg, path, location} objects.Required handlingNo action required — use the returned value as needed.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2]
- body · validation-errors-silenterrorWhenThe field fails validation (e.g., notEmpty(), isEmail())ReturnsError is added to the request's validation error list. Request processing continues to the next middleware. No HTTP error is sent automatically.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false. Without this check, invalid data silently reaches business logic.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- body · successinfoWhenField passes all validation rulesReturnsNo error is added. Request continues normally.Required handlingNo action required — use the returned value as needed.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- check · validation-errors-silenterrorWhenThe field fails validationReturnsError is added to the request's validation error list. Request processing continues.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false. Without this check, invalid data silently reaches business logic.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- check · successinfoWhenField passes all validation rulesReturnsNo error is added. Request continues normally.Required handlingNo action required — use the returned value as needed.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- query · validation-errors-silenterrorWhenThe query parameter fails validationReturnsError is added to the request's validation error list. Request processing continues.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- query · successinfoWhenQuery parameter passes all validation rulesReturnsNo error is added. Request continues normally.Required handlingNo action required — use the returned value as needed.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- param · validation-errors-silenterrorWhenThe route parameter fails validationReturnsError is added to the request's validation error list. Request processing continues.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- param · successinfoWhenRoute parameter passes all validation rulesReturnsNo error is added. Request continues normally.Required handlingNo action required — use the returned value as needed.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- cookie · cookie-validation-errors-silenterrorWhenThe cookie field fails validation (e.g., notEmpty(), isUUID())ReturnsError is added to the request's validation error list. Request processing continues.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false. Without this check, invalid cookie data silently reaches business logic. Cookie-based auth tokens are a common validation target.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[3]
- cookie · cookie-successinfoWhenCookie field passes all validation rulesReturnsNo error is added. Request continues normally.Required handlingNo action required.costlowin proddegraded serviceusers seedegraded performancevisibilitysilentSources[3]
- header · header-validation-errors-silenterrorWhenThe header field fails validation (e.g., required Authorization header is missing or malformed)ReturnsError is added to the request's validation error list. Request processing continues.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false. Header validation often checks auth tokens or API keys — failure to check means unauthorized requests may reach protected business logic.costhighin prodsilent failureusers seelost datavisibilitysilentSources[3]
- header · header-successinfoWhenHeader field passes all validation rulesReturnsNo error is added. Request continues normally.Required handlingNo action required.costlowin proddegraded serviceusers seedegraded performancevisibilitysilentSources[3]
- checkSchema · checkschema-validation-errors-silenterrorWhenOne or more fields in the schema fail their validation rulesReturnsErrors are added to the request's validation error list. Request processing continues to the next middleware. No HTTP error is sent automatically.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false. checkSchema() is commonly used for complex multi-field forms — failure to check means all field errors are silently ignored and invalid data reaches business logic.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[4]
- checkSchema · checkschema-run-result-not-checkederrorWhencheckSchema chains are invoked with .run(req) but validationResult is not called afterwardReturnsValidation runs but results are discarded. All validated fields pass through to the handler regardless of validity.Required handlingWhen using checkSchema chains programmatically with .run(req), always call validationResult(req) in the route handler afterward. The .run() persists errors to req (dryRun: false by default), so validationResult will see them — but only if called.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[5]
- oneOf · oneof-all-chains-failed-error-not-checkederrorWhenNone of the provided validation chains pass, but validationResult() is not calledReturnsA single AlternativeValidationError (or GroupedAlternativeValidationError) is added to the request with nested errors. Request continues to the route handler, which silently processes the invalid input.Required handlingRoute handler MUST call validationResult(req) and check isEmpty(). With oneOf(), errors are nested under nestedErrors — the alternative error wraps all chain errors. Accessing errors.array() returns the top-level alternative error. Use error.nestedErrors to inspect which alternatives failed and why.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[6]
- oneOf · oneof-nested-errors-not-inspectedwarningWhenvalidationResult() is called and errors exist from oneOf(), but only the top-level error is inspected without examining nestedErrorsReturnsThe top-level AlternativeValidationError is returned. The nestedErrors property contains the actual per-chain failures but is never read, so users receive a generic error message instead of actionable field-level errors.Required handlingFor user-facing error messages, access error.nestedErrors to get per-chain failure details. The errorType option controls structure: 'flat' provides all errors in one array; 'least_errored' shows only the closest-to-passing chain; 'grouped' (default) groups by chain group.costlowin proddegraded serviceusers seedegraded performancevisibilityvisibleSources[6]
- checkExact · checkexact-unknown-fields-not-checkederrorWhenRequest contains fields not covered by any validation chain, but validationResult() is not calledReturnsA UnknownFieldsError with type 'unknown_fields' is added to the request. The unknownFields property lists all unexpected fields. Request continues to the route handler, which may process the unexpected data.Required handlingRoute handler MUST call validationResult(req) and return an error response when isEmpty() is false. The UnknownFieldsError has an unknownFields property listing all unexpected fields and their locations. Without this check, mass-assignment attacks succeed — users can submit arbitrary fields that bypass your validation schema.costhighin prodsilent failureusers seelost datavisibilitysilentSources[7]
- checkExact · checkexact-ordering-violationerrorWhencheckExact() is placed BEFORE other validation middleware in the routeReturnsFields validated by middleware that runs after checkExact() are incorrectly flagged as unknown fields. This generates false-positive UnknownFieldsErrors that block valid requests.Required handlingAlways place checkExact() as the LAST validation middleware before the route handler. It only recognizes fields for which validation chains were registered before it runs.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[7]
- run · run-result-not-checkederrorWhen.run(req) is awaited but neither the returned ResultWithContext is checked, nor is validationResult(req) called afterward in the route handlerReturnsValidation runs and errors are stored on the request, but if the caller never checks them, all validation errors are silently ignored. The handler proceeds with potentially invalid data.Required handlingAfter await chain.run(req), EITHER check the returned result directly (result.isEmpty(), result.array()) OR call validationResult(req) in the handler. The most common pattern: await chain.run(req); const errors = validationResult(req); if (\!errors.isEmpty()) { return res.status(400).json(...); }costmediumin prodsilent failureusers seelost datavisibilitysilentSources[5]
- run · run-not-awaitederrorWhen.run(req) is called without await (fire-and-forget)ReturnsValidation starts asynchronously but completes after the route handler has already continued. Errors are never persisted to req. validationResult(req) returns empty. All fields silently pass validation.Required handlingAlways await chain.run(req). Fire-and-forget causes silent validation skips that are extremely difficult to debug — validationResult appears to pass even when fields are invalid.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[5]
- matchedData · matcheddata-used-without-validationresult-checkerrorWhenmatchedData(req) is called but the caller did NOT first call validationResult(req) and check isEmpty() — invalid fields silently absent from the returned objectReturnsReturns an object that silently omits all fields that failed validation. If the caller assumes all submitted fields are present (e.g., spreading into a DB write), invalid user input is treated as missing rather than invalid — no error is thrown.Required handlingAlways call validationResult(req) and verify isEmpty() before calling matchedData(req). Without this check, the returned object silently excludes invalid fields. Code that does `db.update({ ...matchedData(req) })` without first verifying validation passed will silently persist partial data or update with undefined fields.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[8]
- matchedData · matcheddata-optional-fields-silently-absentwarningWhenmatchedData(req) is called without { includeOptionals: true } but the code assumes all validated optional fields are present in the returned objectReturnsOptional fields that were not included in the request are absent from the result by default. Code that destructures matchedData() and assigns directly to a record update will silently skip optional fields, leaving stale values unchanged instead of clearing them (e.g., a user attempting to unset an optional profile field).Required handlingPass { includeOptionals: true } when you need optional fields present (even as undefined) in the returned object. Otherwise, distinguish between "user didn't submit this field" (absent) and "user submitted this field as empty" using req.body directly for optional fields. Failure to handle this causes silent PATCH semantics even when a PUT was intended.costlowin prodsilent failureusers seelost datavisibilitysilentSources[8]
- ExpressValidator · express-validator-custom-sanitizer-no-returnerrorWhenA custom sanitizer registered with new ExpressValidator() does not return a value (or implicitly returns undefined)ReturnsThe field's value is silently set to undefined. Validation technically "succeeds" — no error is added — but the field value is permanently corrupted to undefined in the request context. Any subsequent matchedData() call will include the field as undefined. DB writes using the field will store null/undefined.Required handlingCustom sanitizers MUST return a value. The official docs warn: "If you don't return from a custom sanitizer, your field will become undefined!" This is a silent data corruption — no exception is thrown, validation passes, but the field is destroyed. Always explicitly return the sanitized value.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[9]
- ExpressValidator · express-validator-async-validator-swallows-infra-errorwarningWhenA custom async validator performs a database or network call that rejects due to an infrastructure error (DB timeout, network failure), but the calling code does not distinguish validation failures from infrastructure failuresReturnsThe field is marked as invalid (same as a real validation failure). No exception propagates — the promise rejection is caught internally and converted to a validation error. validationResult(req) reports the field as invalid. The underlying DB/network error is silently consumed with no alerting, logging, or 500 response.Required handlingCustom async validators that make DB or network calls should catch and re-throw infrastructure errors separately. Pattern: if the error is a DB/network error (not a business rule failure), rethrow so that the route can return 500 instead of 422. Without this, a DB timeout silently looks like "invalid email" to the user.costmediumin proddegraded serviceusers seedegraded performancevisibilityvisibleSources[9]
- result-throw · result-throw-no-trycatcherrorWhenvalidationResult(req).throw() is called in a route handler not wrapped in try-catch and not using express-async-errors or Express 5ReturnsIf validation errors exist, throws an unhandled exception. Express 4's default error handler returns a 500 Internal Server Error rather than a 400 Bad Request. This leaks validation state as a server error and may expose internal error details to clients.Required handlingEither: (a) wrap in try-catch and send a structured 400 response, or (b) use express-async-errors (patches Express to handle async throws), or (c) use Express 5 which handles async route errors natively. In Express 4 without async-errors, throw() produces a 500, not a 400, and may expose error details.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10]
- result-throw · result-throw-successinfoWhenNo validation errors exist when .throw() is calledReturnsReturns void without throwing. Execution continues normally.Required handlingNo action required.costlowin proddegraded serviceusers seedegraded performancevisibilitysilentSources[10]
- validationResult.withDefaults · withdefaults-formatter-throwserrorWhenThe custom formatter passed to validationResult.withDefaults() destructures or accesses a property that may be absent on some ValidationError subtypes (e.g. `.path` on AlternativeValidationError / GroupedAlternativeValidationError / UnknownFieldsError), and .array()/.mapped() is called on the returned Result without a try-catch around the response-building codeReturnsThe formatter throws when invoked over a non-field-shaped error. The throw propagates out of res.json({ errors: errors.array() }) and is caught by Express's default error handler, which returns a 500 Internal Server Error instead of the intended 400. Stack traces may leak in development mode and the user sees an opaque server error instead of the actual validation feedback. With oneOf()/checkExact() in the route, this turns a legitimate 400 into a misleading 500 on every failing request.Required handlingThe formatter MUST handle every ValidationError subtype safely. Use `error.type` to discriminate (`'field'` | `'alternative'` | `'alternative_grouped'` | `'unknown_fields'`) before reaching for type-specific properties. Pattern: `const field = error.type === 'field' ? error.path : '_' + error.type;`. Alternatively, wrap response-building in try-catch and fall back to a generic 400 if the formatter throws — but discriminating on .type is the canonical fix.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
- validationResult.withDefaults · withdefaults-formatter-side-effectwarningWhenThe custom formatter performs side effects (logging, metrics, DB writes) on every error in the result, but the same Result instance is materialized multiple times (e.g. .array() called inside a loop or in both the response and an audit log)ReturnsThe formatter runs once per error per .array()/.mapped() call. If the formatter logs to an external sink, the same error is logged N times where N is the number of materializations, inflating log volumes and skewing per-error rate metrics.Required handlingKeep the formatter pure — return the formatted error, do not log or write inside it. Side effects belong outside .array(), in the response handler, where you control the materialization count.costlowin proddegraded serviceusers seedegraded performancevisibilitysilentSources[11]
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
Official documentation
- [1]express-validator.github.io/docs/guides/getting-startedGetting Started
- [2]express-validator.github.io/docs/api/validation-resultValidation Result
- [3]express-validator.github.io/docs/api/validation-chain-buildersValidation Chain Builders
- [4]express-validator.github.io/docs/api/check-schemaCheck Schema
- [5]express-validator.github.io/docs/guides/manually-runningManually Running
- [6]express-validator.github.io/docs/api/one-ofOne Of
- [7]express-validator.github.io/docs/api/check-exactCheck Exact
- [8]express-validator.github.io/docs/api/matched-dataMatched Data
- [9]express-validator.github.io/docs/guides/customizingCustomizing
- [10]express-validator.github.io/docs/api/validation-resultValidation Result
- [11]express-validator.github.io/docs/api/validation-resultValidation Result
- [12]express-validator.github.io/docs/api/validation-errorsValidation Errors
Research notes
Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.
Sources: express-validator
Official Documentation
Research Date: 2026-02-26
Need a different package?
Request a profile