{"record":{"id":"5e7b4ce08a5bca67","repo":"Automattic/mongoose","slug":"cast-to-string-failed-for-value-value-at-path","errorCode":null,"errorMessage":"Cast to string failed for value \"${value}\" at path \"${path}\"","messagePattern":"Cast to string failed for value \"(.+?)\" at path \"(.+?)\"","errorType":"exception","errorClass":"CastError","httpStatus":null,"severity":"error","filePath":"lib/cast/string.js","lineNumber":36,"sourceCode":"  if (value == null) {\n    return value;\n  }\n\n  // handle documents being passed\n  if (typeof value?._id === 'string') {\n    return value._id;\n  }\n\n  // Re: gh-647 and gh-3030, we're ok with casting using `toString()`\n  // **unless** its the default Object.toString, because \"[object Object]\"\n  // doesn't really qualify as useful data\n  if (value.toString &&\n      value.toString !== Object.prototype.toString &&\n      !Array.isArray(value)) {\n    return value.toString();\n  }\n\n  throw new CastError('string', value, path);\n};\n","sourceCodeStart":18,"sourceCodeEnd":38,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/cast/string.js#L18-L38","documentation":"The string caster accepts primitives and any object with a custom toString(), but refuses arrays and objects whose toString is still Object.prototype.toString -- '[object Object]' is not real data (gh-647, gh-3030). Values matching neither rule produce CastError('string', value, path).","triggerScenarios":"doc.name = ['a', 'b']; doc.name = {}; nested objects from req.body assigned to a String path. Dates and other built-ins with custom toString() are fine; arrays never are.","commonSituations":"Multi-value form fields; JSON where a string field arrives as an object or array; subdocuments assigned to string paths; DTO fields typed as arrays upstream.","solutions":["Convert explicitly: doc.name = String(value), or value.join(', ') for arrays","Pick the right property from the object: doc.name = obj.name","Change the schema path to [String] if arrays of strings are the real payload"],"exampleFix":"// before\ndoc.code = ['US', 'NY']; // assigned to a String path\n\n// after\ndoc.code = ['US', 'NY'].join('-'); // explicit conversion","handlingStrategy":"type-guard","validationCode":"function toStringValue(v) {\n  if (v == null) return v;\n  if (Array.isArray(v)) return v.join(', ');\n  if (typeof v === 'object') throw new TypeError('Expected a string, got object');\n  return String(v);\n}\ndoc.code = toStringValue(req.body.code);","typeGuard":"function isStringCastable(v) {\n  if (v == null) return true;\n  if (typeof v !== 'object') return true;\n  return typeof v.toString === 'function' &&\n    v.toString !== Object.prototype.toString;\n}","tryCatchPattern":"try {\n  await doc.save();\n} catch (err) {\n  if (err.name === 'CastError' && err.kind === 'string') {\n    // err.value is the array/plain object; convert it explicitly and retry\n  }\n  throw err;\n}","preventionTips":["Validate request payloads with a schema that enforces string types","Convert arrays at the boundary (join or reject)","Remember mongoose auto-extracts _id from documents -- assign that instead of the whole object"],"tags":["mongoose","string","cast","objects"],"backgroundTag":"string-cast-failed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}