{"record":{"id":"f5c5a73c7cc98552","repo":"Automattic/mongoose","slug":"cast-to-embedded-failed-for-value-value-type-f5c5a7","errorCode":null,"errorMessage":"Cast to Embedded failed for value \"${value}\" (type ${valueType}) at path \"${path}\"","messagePattern":"Cast to Embedded failed for value \"(.+?)\" \\(type (.+?)\\) at path \"(.+?)\"","errorType":"validation","errorClass":"CastError","httpStatus":null,"severity":"error","filePath":"lib/schema/subdocument.js","lineNumber":264,"sourceCode":"  }\n\n  const Constructor = getConstructor(this.Constructor, val);\n  if (val instanceof Constructor) {\n    return val;\n  }\n\n  if (this.options.runSetters) {\n    val = this._applySetters(val, context);\n  }\n\n  const overrideStrict = options?.strict ?? void 0;\n\n  try {\n    val = new Constructor(val, overrideStrict);\n  } catch (error) {\n    // Make sure we always wrap in a CastError (gh-6803)\n    if (!(error instanceof CastError)) {\n      throw new CastError('Embedded', val, this.path, error, this);\n    }\n    throw error;\n  }\n  return val;\n};\n\n/**\n * Async validation on this single nested doc.\n *\n * @api public\n */\n\nSchemaSubdocument.prototype.doValidate = async function doValidate(value, scope, options) {\n  const Constructor = getConstructor(this.Constructor, value);\n\n  if (value && !(value instanceof Constructor)) {\n    value = new Constructor(value, null, scope?.$__ != null ? scope : null);\n  }","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/schema/subdocument.js#L246-L282","documentation":"When casting a query/update value into a single-nested subdocument, mongoose runs `new Constructor(val)`. Any failure that is not already a CastError is wrapped as `Cast to Embedded failed ... at path` (gh-6803) so callers always get a CastError; the underlying error is preserved on `err.reason`.","triggerScenarios":"`Model.find({ nested: 'not-an-object' })` where the value cannot be constructed into the subschema; custom setters on the subschema that throw TypeErrors during construction; `$set` updates with values the subdocument constructor rejects.","commonSituations":"Passing primitives where objects are expected in filters; discriminator construction mismatches; bugs in custom setters that only surface during query casting.","solutions":["Pass a plain object (or query the subfield with a dotted path) instead of a primitive","Inspect `err.reason` and the original message to find the real failure inside the subschema","Fix or make exception-safe any custom setter/transform on the subschema that throws non-CastError errors","Cast the value yourself (`new Subdoc(value)`) inside try/catch to surface the raw error during development"],"exampleFix":"// before\nModel.find({ nested: 'x' }); // throws Cast to Embedded failed\n\n// after\nModel.find({ 'nested.name': 'x' }); // query the subfield directly","handlingStrategy":"try-catch","validationCode":"function isCastableSubdocValue(v) {\n  return v == null || (typeof v === 'object' && !Array.isArray(v));\n}","typeGuard":"const isCastableSubdocValue = v => v == null || (typeof v === 'object' && !Array.isArray(v));","tryCatchPattern":"try {\n  const docs = await Model.find({ nested: raw });\n} catch (err) {\n  if (err instanceof mongoose.Error.CastError && err.kind === 'Embedded') {\n    const root = err.reason; // underlying constructor/setter failure\n    // reject the request payload and include err.path + root.message in diagnostics\n  } else throw err;\n}","preventionTips":["Always read `err.reason` on Embedded CastErrors — the real cause is nested there (gh-6803)","Query subfields with dotted paths instead of passing whole values for the embedded path","Make custom setters exception-safe or rethrow CastErrors so wrapping stays informative"],"tags":["mongoose","subdocument","cast","query","casterror"],"backgroundTag":"value-cast-failed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}