{"record":{"id":"f1f7f977a93a2bd1","repo":"Automattic/mongoose","slug":"cast-to-number-failed-value-is-not-a-valid-number","errorCode":null,"errorMessage":"Cast to Number failed: value is not a valid number","messagePattern":"Cast to Number failed: value is not a valid number","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/cast/number.js","lineNumber":26,"sourceCode":" * @return {number}\n * @throws {Error} if `value` is not one of the allowed values\n * @api private\n */\n\nmodule.exports = function castNumber(val) {\n  if (val == null) {\n    return val;\n  }\n  if (val === '') {\n    return null;\n  }\n\n  if (typeof val === 'string' || typeof val === 'boolean') {\n    val = Number(val);\n  }\n\n  if (isNaN(val)) {\n    throw new Error('Cast to Number failed: value is not a valid number');\n  }\n  if (val instanceof Number) {\n    return val.valueOf();\n  }\n  if (typeof val === 'number') {\n    return val;\n  }\n  if (!Array.isArray(val) && typeof val.valueOf === 'function') {\n    return Number(val.valueOf());\n  }\n  if (val.toString && !Array.isArray(val) && val.toString() == Number(val)) {\n    return Number(val);\n  }\n\n  throw new Error('Cast to Number failed: value is not a valid number');\n};\n","sourceCodeStart":8,"sourceCodeEnd":43,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/cast/number.js#L8-L43","documentation":"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.","triggerScenarios":"doc.age = 'abc' | '12px' | '1,000.50' | 'N/A'; doc.n = {}; doc.n = ['a', 'b'] (Number() gives NaN); Model.find({ price: '1,000' }).","commonSituations":"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.","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"],"exampleFix":"// before\ndoc.price = '1,000.50'; // Number('1,000.50') -> NaN\n\n// after\ndoc.price = Number('1,000.50'.replace(/,/g, ''));","handlingStrategy":"validation","validationCode":"function toNumberOrNull(v) {\n  if (v == null || v === '') return null;\n  const n = typeof v === 'string' || typeof v === 'boolean' ? Number(v) : v;\n  if (typeof n !== 'number' || Number.isNaN(n)) {\n    throw new TypeError(`Not a valid number: ${JSON.stringify(v)}`);\n  }\n  return n;\n}\ndoc.price = toNumberOrNull(req.body.price);","typeGuard":"function isCastableNumber(v) {\n  if (v == null || v === '') return true;\n  const n = typeof v === 'string' || typeof v === 'boolean' ? Number(v) : v;\n  return typeof n === 'number' && !Number.isNaN(n);\n}","tryCatchPattern":"try {\n  await doc.save();\n} catch (err) {\n  if (err.message === 'Cast to Number failed: value is not a valid number') {\n    // find the offending field via the wrapped ValidationError's err.path\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["mongoose","number","cast","nan"],"backgroundTag":"number-cast-failed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}