{"record":{"id":"636d7a0695cf6f23","repo":"Automattic/mongoose","slug":"field-path-is-not-in-schema-and-strict-mode-i","errorCode":null,"errorMessage":"Field `${path}` is not in schema and strict mode is set to throw.","messagePattern":"Field `(.+?)` is not in schema and strict mode is set to throw\\.","errorType":"exception","errorClass":"StrictModeError","httpStatus":null,"severity":"error","filePath":"lib/cast.js","lineNumber":299,"sourceCode":"                  value = value.toObject({ virtuals: false });\n                }\n              }\n            }\n\n            _cast(value, numbertype, context);\n            continue;\n          }\n        }\n\n        if (schema.nested[path]) {\n          continue;\n        }\n\n        const strict = 'strict' in options ? options.strict : schema.options.strict;\n        const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options, context);\n        if (options.upsert && strict) {\n          if (strict === 'throw') {\n            throw new StrictModeError(path);\n          }\n          throw new StrictModeError(path, 'Path \"' + path + '\" is not in ' +\n            'schema, strict mode is `true`, and upsert is `true`.');\n        } if (strictQuery === 'throw') {\n          throw new StrictModeError(path, 'Path \"' + path + '\" is not in ' +\n            'schema and strictQuery is \\'throw\\'.');\n        } else if (strictQuery) {\n          delete obj[path];\n        }\n      } else if (val == null) {\n        continue;\n      } else if (utils.isPOJO(val)) {\n        any$conditionals = Object.keys(val).some(isOperator);\n\n        if (!any$conditionals) {\n          obj[path] = schematype.castForQuery(\n            null,\n            val,","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/cast.js#L281-L317","documentation":"While casting an upsert, mongoose found a path that is not in the schema and strict mode resolved to 'throw'. StrictModeError exists to surface unknown fields instead of silently dropping them; the upsert flag makes any truthy strict setting fatal, and 'throw' produces this default message naming the field.","triggerScenarios":"Model.updateOne(filter, { notInSchema: 1 }, { upsert: true }) on a schema defined with { strict: 'throw' }; the same via findOneAndUpdate; passing { strict: 'throw' } inside the options of a single call.","commonSituations":"Upserting API payloads that carry extra metadata (tenant id, client version) never added to the schema; field-name typos; payloads shared with insert paths that ran under strict: false; enabling strict: 'throw' during a data-hygiene audit.","solutions":["Declare the field in the schema (or fix the typo) so the path is known","Strip unknown keys from the update document before calling updateOne with upsert: true","Allow it for this call only: Model.updateOne(filter, update, { upsert: true, strict: false })","Store genuinely schemaless extras under a declared Mixed path instead of top level"],"exampleFix":"// before\nconst schema = new Schema({ name: String }, { strict: 'throw' });\nawait Model.updateOne({ name: 'x' }, { name: 'x', counter: 1 }, { upsert: true });\n\n// after\nconst schema = new Schema({ name: String, counter: Number }, { strict: 'throw' });\nawait Model.updateOne({ name: 'x' }, { name: 'x', counter: 1 }, { upsert: true });","handlingStrategy":"validation","validationCode":"function findUnknownPaths(Model, doc) {\n  return Object.keys(doc).filter(\n    k => !(k in Model.schema.paths) && !Model.schema.nested[k]\n  );\n}\nconst unknown = findUnknownPaths(Model, update);\nif (unknown.length > 0 && opts.upsert) {\n  throw new Error(`Refusing upsert with unknown paths: ${unknown.join(', ')}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Model.updateOne(filter, update, { upsert: true });\n} catch (err) {\n  if (err.name === 'StrictModeError') {\n    // err.path names the unknown field; add it to the schema or delete it from `update`\n  }\n  throw err;\n}","preventionTips":["Model every field you upsert; keep schema and API contract in sync","Pick modeled fields explicitly instead of forwarding whole request bodies","Run integration tests for each upsert endpoint so unknown fields fail in CI, not production"],"tags":["mongoose","strict-mode","upsert","schema"],"backgroundTag":"strict-mode-violation","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}