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
- Clean the value first: strip non-numeric characters, e.g. Number(String(v).replace(/[^0-9.eE+-]/g, ''))
- Send real JSON numbers from clients instead of strings
- 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
- Validate numeric inputs at the API boundary (zod/Joi number coercion)
- Normalize locale-specific formats before import
- Never feed raw string query params into numeric filters
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
- Cast to Number failed for value "${value}" (type ${valueType
- Query filter must be an object, got an array ${util.inspect(
- Cast to Array failed for value "${value}" at path "${path}"
- Cast to Object failed for value "${value}" at path "${path}.
- Mongoose only supports BigInts between -9223372036854775808
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/f1f7f977a93a2bd1.
Report an issue: GitHub.