validatorjs/validator.js · error · TypeError

Expected a string but received a ${input.constructor.name}

Error message

Expected a string but received a ${input.constructor.name}

What it means

assertString throws this TypeError when the input is neither undefined nor null but its constructor name is not 'String' — i.e. a number, object, array, boolean, or a String object from another realm/way. It fires at the entry of most public validators (isAlpha, contains, equals, blacklist, isAbaRouting, etc.) to guarantee the argument is a primitive string, since the library does not coerce types.

Source

Thrown at src/lib/util/assertString.js:3

export default function assertString(input) {
  if (input === undefined || input === null) throw new TypeError(`Expected a string but received a ${input}`);
  if (input.constructor.name !== 'String') throw new TypeError(`Expected a string but received a ${input.constructor.name}`);
}

View on GitHub (pinned to a79ff980ab)

Solutions

  1. Convert explicitly with String(value) (or value.toString() for safe object types like ObjectId) before calling the validator.
  2. For primitives other than strings, decide whether string conversion is semantically correct — String(123) is fine for isInt, but String({}) produces '[object Object]' and hides the bug.
  3. Fix the typing at the source: enforce string types with TypeScript, schema validation (zod/joi), or form input coercion so non-strings never reach the validator.
  4. Watch for String wrapper objects: use value.valueOf() or String(value) to unwrap new String('...') instances.

Example fix

// before
if (validator.isAlpha(zipCode)) { ... } // zipCode = 90210 (number) -> TypeError
// after
const zip = typeof zipCode === 'string' ? zipCode : String(zipCode ?? '');
if (validator.isAlpha(zip)) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

function assertPrimitiveString(v, name = 'value') {
  if (typeof v !== 'string') {
    throw new TypeError(`${name} must be a primitive string, received: ${Object.prototype.toString.call(v)}`);
  }
  return v;
}
// usage: validator.isAbaRouting(assertPrimitiveString(routingNumber, 'routingNumber'))

Type guard

function isPrimitiveString(v) {
  return typeof v === 'string';
}
// typeof excludes String wrapper objects too: typeof new String('a') === 'object'

Try / catch

try {
  return validator.isAbaRouting(input);
} catch (e) {
  if (e instanceof TypeError && e.message.startsWith('Expected a string but received a')) {
    console.error(`Non-string passed to validator: ${e.message}`);
    return false;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a number (validator.isAlpha(12345)), a Date, a parsed JSON object/array, a Boolean, a String wrapper object (new String('abc')), or a cross-realm string (e.g. from vm/iframe) whose constructor.name differs, to any validator or sanitizer expecting a string.

Common situations: Numeric form/query inputs not converted to string before validation; Number() results fed to isInt-like checks that still require strings; MongoDB/ObjectId or Decimal objects used directly; template-free values from config files typed as numbers; code that worked with loosely-typed data later run through the validator unchanged.

Related errors


AI-assisted analysis of validatorjs/validator.js@a79ff980ab (2026-08-31). Data as JSON: /api/errors/2b72f52609c79456. Report an issue: GitHub.