{"record":{"id":"7999b6164f055940","repo":"Automattic/mongoose","slug":"cannot-use-schema-level-projections-select-true","errorCode":null,"errorMessage":"Cannot use schema-level projections (`select: true` or `select: false`) within maps at path \"${path}.${subpath}\"","messagePattern":"Cannot use schema-level projections \\(`select: true` or `select: false`\\) within maps at path \"(.+?)\\.(.+?)\"","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/schema/map.js","lineNumber":182,"sourceCode":"  const mapPath = path + '.$*';\n  let _mapType = { type: {} };\n  if (utils.hasUserDefinedProperty(obj, 'of')) {\n    const isInlineSchema = utils.isPOJO(obj.of) &&\n      utils.hasOwnKeys(obj.of) &&\n      !utils.hasUserDefinedProperty(obj.of, schema.options.typeKey);\n    if (isInlineSchema) {\n      _mapType = { [schema.options.typeKey]: new Schema(obj.of) };\n    } else if (utils.isPOJO(obj.of)) {\n      _mapType = Object.assign({}, obj.of);\n    } else {\n      _mapType = { [schema.options.typeKey]: obj.of };\n    }\n\n    if (_mapType[schema.options.typeKey] && _mapType[schema.options.typeKey].instanceOfSchema) {\n      const subdocumentSchema = _mapType[schema.options.typeKey];\n      subdocumentSchema.eachPath((subpath, type) => {\n        if (type.options.select === true || type.options.select === false) {\n          throw new MongooseError('Cannot use schema-level projections (`select: true` or `select: false`) within maps at path \"' + path + '.' + subpath + '\"');\n        }\n      });\n    }\n\n    if (utils.hasUserDefinedProperty(obj, 'ref')) {\n      _mapType.ref = obj.ref;\n    }\n  }\n  this.$__schemaType = schema.interpretAsType(mapPath, _mapType, options);\n};\n\nmodule.exports = SchemaMap;\n","sourceCodeStart":164,"sourceCodeEnd":195,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/schema/map.js#L164-L195","documentation":"When interpreting a Map of subdocuments, Mongoose walks every path of the value schema and throws if any path declares an explicit `select: true` or `select: false`. Projection options on subpaths inside a Map are unsupported (projections are resolved per top-level path and Map subpaths do not map cleanly onto projection documents), so Mongoose refuses the schema at definition time rather than silently ignoring the option.","triggerScenarios":"`new Schema({ data: { type: Map, of: new Schema({ secret: { type: String, select: false } }) } })` — any Map whose `of` resolves to a schema containing a path with select true/false. Note the check runs on the *value* schema's paths via eachPath, so even nested subdocument paths with select trigger it.","commonSituations":"Reusing an existing subdocument schema (with hidden fields like password hashes or tokens) as the `of` type of a Map; adding `select: false` for security without noticing the schema is embedded in a Map; schema libraries sharing a base sub-schema across Map and non-Map parents.","solutions":["Remove `select` from the map's value schema paths; hide those fields at query time with an explicit projection on the parent (`.select('-data')` or field filtering in the serializer layer)","Clone the value schema and strip select options before passing it as `of`: `const s = base.clone(); s.eachPath((p, t) => delete t.options.select)`","Restructure to a plain subdocument array path (`items: [base]`) where select is honored, or keep secrets in a separate model","Enforce a lint/review rule: no select options inside Map-of-subdocument definitions"],"exampleFix":"// before\nconst secretSchema = new Schema({ token: { type: String, select: false } });\nnew Schema({ apiKeys: { type: Map, of: secretSchema } });\n\n// after\nconst secretSchema = new Schema({ token: String });\nnew Schema({ apiKeys: { type: Map, of: secretSchema } });\n// and filter token out in the response layer (toJSON transform or serializer)","handlingStrategy":"validation","validationCode":"function stripSelectOptions(subSchema) {\n  subSchema.eachPath((p, type) => { delete type.options.select; });\n  return subSchema;\n}\nnew Schema({ data: { type: Map, of: stripSelectOptions(baseSchema.clone()) } });","typeGuard":null,"tryCatchPattern":"try { new Schema({ data: { type: Map, of: valueSchema } }); } catch (err) { if (/schema-level projections/.test(err.message)) { stripSelectOptions(valueSchema); } else throw err; }","preventionTips":["Keep select projections on top-level paths only","Filter secret fields in the serializer/toJSON layer instead of Map subschemas","Lint for select options inside Map `of` definitions"],"tags":["mongoose","map","schema","projection","select"],"backgroundTag":"invalid-schema-option","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}