{"record":{"id":"eafbaed26e9b7f99","repo":"Automattic/mongoose","slug":"cast-to-array-failed-for-value-value-type-eafbae","errorCode":null,"errorMessage":"Cast to Array failed for value \"${value}\" (type ${valueType}) at path \"${path}\"","messagePattern":"Cast to Array failed for value \"(.+?)\" \\(type (.+?)\\) at path \"(.+?)\"","errorType":"exception","errorClass":"CastError","httpStatus":null,"severity":"error","filePath":"lib/schema/array.js","lineNumber":424,"sourceCode":"        // rethrow\n        throw new CastError('[' + e.kind + ']', util.inspect(value), this.path + '.' + i, e, this);\n      }\n    }\n\n    return value;\n  }\n\n  const castNonArraysOption = this.options.castNonArrays ?? SchemaArray.options.castNonArrays;\n  if (init || castNonArraysOption) {\n    // gh-2442: if we're loading this from the db and its not an array, mark\n    // the whole array as modified.\n    if (doc && init) {\n      doc.markModified(this.path);\n    }\n    return this.cast([value], doc, init);\n  }\n\n  throw new CastError('Array', util.inspect(value), this.path, null, this);\n};\n\n/*!\n * ignore\n */\n\nSchemaArray.prototype._castForPopulate = function _castForPopulate(value, doc) {\n  // lazy load\n  MongooseArray || (MongooseArray = require('../types').Array);\n\n  if (Array.isArray(value)) {\n    let i;\n    const rawValue = value.__array ? value.__array : value;\n    const len = rawValue.length;\n\n    if (this.embeddedSchemaType && this.embeddedSchemaType.constructor !== Mixed) {\n      try {\n        for (i = 0; i < len; i++) {","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/schema/array.js#L406-L442","documentation":"Assigning a non-array value to an array path during a set/save (not a database load) throws CastError Array: mongoose will not guess how to coerce a scalar or arbitrary object into the array shape. Only init from the database or an enabled castNonArrays option allow scalar-to-[scalar] coercion.","triggerScenarios":"`doc.numbers = 5` with `numbers: [Number]`; req.body delivering 'a,b,c' (a comma-joined string) where the schema wants [String]; an update $set writing an object onto an array of primitives.","commonSituations":"Form submissions and query strings producing joined strings; upstream APIs silently switching a field from array to scalar; forgetting split() before assignment.","solutions":["Assign an array: `doc.numbers = [5]`; split joined strings before assigning.","Enable lenient coercion where acceptable: per-path `{ type: [String], castNonArrays: true }` or globally `mongoose.Schema.Types.Array.options.castNonArrays = true`.","Normalize payload shapes at the API boundary so arrays stay arrays."],"exampleFix":"// before\ndoc.tags = req.body.tags; // 'red,blue' -> CastError Array\n\n// after\ndoc.tags = Array.isArray(req.body.tags)\n  ? req.body.tags\n  : String(req.body.tags).split(',').map(s => s.trim());","handlingStrategy":"validation","validationCode":"const toArray = (v) =>\n  Array.isArray(v) ? v\n  : (v == null || v === '') ? []\n  : String(v).split(',').map(s => s.trim());\ndoc.tags = toArray(req.body.tags);","typeGuard":"const isArrayInput = (v) => Array.isArray(v);","tryCatchPattern":null,"preventionTips":["Coerce scalars and joined strings to arrays at the request boundary, before they reach models.","Enable castNonArrays only on paths where scalar-to-array is genuinely acceptable.","Watch upstream API changelogs for fields silently switching array to scalar."],"tags":["cast-error","arrays","input-shape","save"],"backgroundTag":"mongoose-cast-error","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}