Automattic/mongoose · error · Error

Cast to Number failed: value is not a valid number

Error message

Cast to Number failed: value is not a valid number

What it means

castNumber passes null through, maps '' to null, converts strings/booleans with Number(), and then throws this Error when the result is NaN. Because the NaN check coerces objects and arrays through Number(), non-numeric strings like 'abc' or '1,000' and objects/arrays that stringify to garbage all land on this throw.

Source

Thrown at lib/cast/number.js:26

 * @return {number}
 * @throws {Error} if `value` is not one of the allowed values
 * @api private
 */

module.exports = function castNumber(val) {
  if (val == null) {
    return val;
  }
  if (val === '') {
    return null;
  }

  if (typeof val === 'string' || typeof val === 'boolean') {
    val = Number(val);
  }

  if (isNaN(val)) {
    throw new Error('Cast to Number failed: value is not a valid number');
  }
  if (val instanceof Number) {
    return val.valueOf();
  }
  if (typeof val === 'number') {
    return val;
  }
  if (!Array.isArray(val) && typeof val.valueOf === 'function') {
    return Number(val.valueOf());
  }
  if (val.toString && !Array.isArray(val) && val.toString() == Number(val)) {
    return Number(val);
  }

  throw new Error('Cast to Number failed: value is not a valid number');
};

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Clean the value first: strip non-numeric characters, e.g. Number(String(v).replace(/[^0-9.eE+-]/g, ''))
  2. Send real JSON numbers from clients instead of strings
  3. Map placeholder values ('N/A', '-') to null before assignment

Example fix

// before
doc.price = '1,000.50'; // Number('1,000.50') -> NaN

// after
doc.price = Number('1,000.50'.replace(/,/g, ''));
Defensive patterns

Strategy: validation

Validate before calling

function toNumberOrNull(v) {
  if (v == null || v === '') return null;
  const n = typeof v === 'string' || typeof v === 'boolean' ? Number(v) : v;
  if (typeof n !== 'number' || Number.isNaN(n)) {
    throw new TypeError(`Not a valid number: ${JSON.stringify(v)}`);
  }
  return n;
}
doc.price = toNumberOrNull(req.body.price);

Type guard

function isCastableNumber(v) {
  if (v == null || v === '') return true;
  const n = typeof v === 'string' || typeof v === 'boolean' ? Number(v) : v;
  return typeof n === 'number' && !Number.isNaN(n);
}

Try / catch

try {
  await doc.save();
} catch (err) {
  if (err.message === 'Cast to Number failed: value is not a valid number') {
    // find the offending field via the wrapped ValidationError's err.path
  }
  throw err;
}

Prevention

When it happens

Trigger: doc.age = 'abc' | '12px' | '1,000.50' | 'N/A'; doc.n = {}; doc.n = ['a', 'b'] (Number() gives NaN); Model.find({ price: '1,000' }).

Common situations: Unsanitized form input carrying units or currency symbols; localized number formats ('1.234,56'); CSV/Excel imports with thousands separators or placeholder text; free-text fields feeding numeric paths.

Related errors


AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21). Data as JSON: /api/errors/f1f7f977a93a2bd1. Report an issue: GitHub.