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
- Convert explicitly with String(value) (or value.toString() for safe object types like ObjectId) before calling the validator.
- 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.
- 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.
- 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
- Convert numerics and objects explicitly (String(x)) at the boundary; avoid implicit coercion into validators.
- Unwrap String wrapper objects with valueOf()/String() — prefer always storing primitive strings.
- Use TypeScript or JSDoc types (@param {string}) so non-string arguments are caught at compile time.
- Beware cross-realm strings (vm, iframes): route such values through String(value) before validation.
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
- Expected a string but received a ${input}
- Invalid locale '${locale}'
- Invalid country code: '${countryCode}'
AI-assisted analysis of validatorjs/validator.js@a79ff980ab (2026-08-31).
Data as JSON: /api/errors/2b72f52609c79456.
Report an issue: GitHub.