Automattic/mongoose · error · CastError
Cast to Number failed for value "${value}" (type ${valueType
Error message
Cast to Number failed for value "${value}" (type ${valueType}) at path "${path}" What it means
SchemaNumber.cast wraps the number caster (lib/cast/number.js) and rethrows failures as CastError 'Number'. Valid input: null/undefined, empty string (→ null), numeric strings ('42'), booleans (true → 1), Number objects, values with numeric valueOf(), and arrays are rejected outright. Strings like 'abc' or '12px' and objects without numeric coercion throw 'Cast to Number failed: value is not a valid number', wrapped into this CastError.
Source
Thrown at lib/schema/number.js:412
}
const val = value?._id !== undefined ?
value._id : // documents
value;
let castNumber;
if (typeof this._castFunction === 'function') {
castNumber = this._castFunction;
} else if (typeof this.constructor.cast === 'function') {
castNumber = this.constructor.cast();
} else {
castNumber = SchemaNumber.cast();
}
try {
return castNumber(val);
} catch (err) {
throw new CastError('Number', val, this.path, err, this);
}
};
/*!
* ignore
*/
function handleSingle(val) {
return this.cast(val);
}
function handleArray(val) {
const _this = this;
if (!Array.isArray(val)) {
return [this.cast(val)];
}
return val.map(function(m) {
return _this.cast(m);View on GitHub (pinned to 49cdab0136)
Solutions
- Coerce explicitly at the boundary: `const n = Number(v); if (Number.isNaN(n)) reject;` then assign
- Strip units/currency first when the format is known: `Number(String(v).replace(/[^0-9.-]/g, ''))`
- For decimals-as-strings with locale commas, normalize separators before casting
- Register a lenient custom caster only if you accept the loss of strictness: `mongoose.Schema.Types.Number.cast(v => ...)`
Example fix
// before
product.price = req.body.price; // '12.99 USD'
// after
const price = Number(String(req.body.price).replace(/[^0-9.-]/g, ''));
if (Number.isNaN(price)) throw new ValidationError('bad price');
product.price = price; Defensive patterns
Strategy: validation
Validate before calling
function toNumber(v) {
if (v == null || v === '') return null;
if (Array.isArray(v)) throw new Error('array is not a number');
const n = typeof v === 'string' || typeof v === 'boolean' ? Number(v) : v;
if (typeof n !== 'number' || Number.isNaN(n)) throw new Error(`not a number: ${v}`);
return n;
}
product.price = toNumber(req.body.price); Type guard
function isNumberLike(v) {
if (v == null || v === '' || typeof v === 'number' || typeof v === 'boolean') return true;
if (typeof v === 'string') return !Number.isNaN(Number(v));
return !Array.isArray(v) && !Number.isNaN(Number(v?.valueOf?.()));
} Try / catch
try { doc.qty = v; } catch (err) { if (err.name === 'CastError' && err.kind === 'Number') { return badRequest(`${err.path} must be a number`); } throw err; } Prevention
- HTML forms send strings — coerce in the request handler
- Strip units/currency before casting
- Validate with zod/joi `.coerce.number()` at the boundary
When it happens
Trigger: `doc.age = 'abc'`, `doc.age = '12px'`, `doc.age = '$10'`, `doc.age = {}`, `doc.age = [5]` (arrays rejected by the caster's guards), or queries like `{ age: { $gt: 'unknown' } }`.
Common situations: HTML form fields always arrive as strings and skip coercion; unit-suffixed input from IoT/CSV feeds ('10px', '5kg'); currency strings; JSON APIs returning numbers as strings; parseInt/parseFloat never applied before assignment.
Related errors
- Query filter must be an object, got an array ${util.inspect(
- Cast to Number failed: value is not a valid number
- Cast to date failed for value "${value}" (type ${valueType})
- Cast to Decimal128 failed for value "${value}" (type ${value
- Cast to Double failed for value "${value}" (type ${valueType
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/4fb8c3d1b8e03033.
Report an issue: GitHub.