{"record":{"id":"89e0475f6a8d7c72","repo":"Automattic/mongoose","slug":"cast-to-double-failed-for-value-value-type","errorCode":null,"errorMessage":"Cast to Double failed for value \"${value}\" (type ${valueType}) at path \"${path}\"","messagePattern":"Cast to Double failed for value \"(.+?)\" \\(type (.+?)\\) at path \"(.+?)\"","errorType":"exception","errorClass":"CastError","httpStatus":null,"severity":"error","filePath":"lib/schema/double.js","lineNumber":189,"sourceCode":" * @param {object} value\n * @param {object} model this value is optional\n * @api private\n */\n\nSchemaDouble.prototype.cast = function(value) {\n  let castDouble;\n  if (typeof this._castFunction === 'function') {\n    castDouble = this._castFunction;\n  } else if (typeof this.constructor.cast === 'function') {\n    castDouble = this.constructor.cast();\n  } else {\n    castDouble = SchemaDouble.cast();\n  }\n\n  try {\n    return castDouble(value);\n  } catch (error) {\n    throw new CastError('Double', value, this.path, error, this);\n  }\n};\n\n/*!\n * ignore\n */\n\nfunction handleSingle(val) {\n  return this.cast(val);\n}\n\nconst $conditionalHandlers = {\n  ...SchemaType.prototype.$conditionalHandlers,\n  $gt: handleSingle,\n  $gte: handleSingle,\n  $lt: handleSingle,\n  $lte: handleSingle\n};","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/schema/double.js#L171-L207","documentation":"SchemaDouble.cast converts failures of the Double caster (lib/cast/double.js) into this CastError. Valid input: null/undefined and empty string (→ null), numbers, BSON Long, strings parsed by BSON's strict `Double.fromString`, and objects whose valueOf()/toString() yields a parseable decimal string. Arrays, plain objects without numeric coercion, and non-decimal strings ('abc') throw.","triggerScenarios":"`doc.ratio = 'abc'`, `doc.ratio = [1.5]` (arrays explicitly rejected), `doc.ratio = {}`, or an object whose `valueOf()` returns a non-parseable string. Query side: `{ ratio: { $gt: 'n/a' } }`.","commonSituations":"Mongoose 8's Double type used with un-sanitized string input from forms or spreadsheets; locale-formatted numbers ('1,5'); expecting JS-style loose Number coercion ('5px' works with Number() but Double.fromString rejects it); passing arrays from destructuring mistakes.","solutions":["Assign plain numbers: `doc.ratio = 1.5`","Strip/validate strings to decimal format before assigning (regex `/^[+-]?\\d+(\\.\\d+)?$/`)","Coerce with `Number(v)` at the boundary and check `Number.isNaN`","For arrays of readings, map to numbers explicitly instead of assigning the array"],"exampleFix":"// before\nmetric.ratio = req.body.ratio; // '1,5' or 'n/a'\n\n// after\nconst ratio = Number(String(req.body.ratio).replace(',', '.'));\nif (Number.isNaN(ratio)) throw new ValidationError('bad ratio');\nmetric.ratio = ratio;","handlingStrategy":"validation","validationCode":"function toDouble(v) {\n  if (v == null || v === '') return null;\n  if (Array.isArray(v)) throw new Error('array is not a double');\n  const n = typeof v === 'number' ? v : Number(String(v).replace(',', '.'));\n  if (Number.isNaN(n)) throw new Error(`not a double: ${v}`);\n  return n;\n}\nmetric.ratio = toDouble(req.body.ratio);","typeGuard":"function isDoubleLike(v) {\n  if (v == null || v === '' || typeof v === 'number') return true;\n  return typeof v === 'string' && !Number.isNaN(Number(v.replace(',', '.')));\n}","tryCatchPattern":"try { doc.ratio = v; } catch (err) { if (err.name === 'CastError' && err.kind === 'Double') { return badRequest(`${err.path} must be a number`); } throw err; }","preventionTips":["Coerce strings to Number at the boundary","Never assign arrays to scalar fields","Validate numeric request fields with zod/joi before they hit models"],"tags":["mongoose","double","cast","validation","bson"],"backgroundTag":"mongoose-cast-error","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}