{"record":{"id":"c24cb09567ed858c","repo":"Automattic/mongoose","slug":"invalid-select-argument-must-be-string-or-objec","errorCode":null,"errorMessage":"Invalid select() argument. Must be string or object.","messagePattern":"Invalid select\\(\\) argument\\. Must be string or object\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/query.js","lineNumber":1203,"sourceCode":"              delete userProvidedFields[field];\n            }\n          });\n        }\n      });\n    } else {\n      const keys = Object.keys(arg);\n      for (let i = 0; i < keys.length; ++i) {\n        const value = arg[keys[i]];\n        const key = keys[i];\n        fields[key] = sanitizeValue(value);\n        userProvidedFields[key] = sanitizeValue(value);\n      }\n    }\n\n    return this;\n  }\n\n  throw new TypeError('Invalid select() argument. Must be string or object.');\n};\n\n/**\n * Enable or disable schema level projections for this query. Enabled by default.\n * Set to `false` to include fields with `select: false` in the query result by default.\n *\n * #### Example:\n *\n *     const userSchema = new Schema({\n *       email: { type: String, required: true },\n *       passwordHash: { type: String, select: false, required: true }\n *     });\n *     const UserModel = mongoose.model('User', userSchema);\n *\n *     const doc = await UserModel.findOne().orFail().schemaLevelProjections(false);\n *\n *     // Contains password hash, because `schemaLevelProjections()` overrides `select: false`\n *     doc.passwordHash;","sourceCodeStart":1185,"sourceCodeEnd":1221,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/query.js#L1185-L1221","documentation":"Mongoose's Query.prototype.select() only accepts projections as a string (e.g. 'name -email') or a plain object (e.g. { name: 1, email: 0 }); falsy arguments (0, false, '') return early as a no-op. The argument is run through parseProjection() and only the object branch can produce a projection, so any remaining truthy non-object value falls through to this terminal TypeError. Passing more than one argument triggers a different, earlier error ('Invalid select: select only takes 1 argument'), so this one specifically means a single value of the wrong type.","triggerScenarios":".select(1), .select(true), or .select(() => buildFields()); passing an unvalidated request value (req.query.fields) that resolves to a number or boolean; passing a variable that was expected to be a projection object but is actually a primitive.","commonSituations":"Dynamically building projections from user input without validating shape; passing a boolean or numeric flag where a projection spec belongs; porting code from other ORMs where any truthy value is stringified into a field list.","solutions":["Pass a string projection like .select('name email') (prefix a field with - to exclude) or an object like .select({ name: 1, email: 0 })","If the projection comes from user input, whitelist allowed field names and build the string/object yourself before calling select()","To clear or no-op the projection, call .select() with no argument or a falsy value","Check the variable you are passing is not accidentally a number, boolean, or function"],"exampleFix":"// before\nconst users = await User.find().select(1);   // TypeError: Invalid select() argument\nconst users2 = await User.find().select(true); // same TypeError\n\n// after\nconst users = await User.find().select('name email');\n// or\nconst users2 = await User.find().select({ name: 1, email: 1 });","handlingStrategy":"type-guard","validationCode":"const ALLOWED_FIELDS = new Set(['name', 'email', 'age']);\nfunction buildProjection(raw) {\n  if (raw == null) return undefined;\n  const fields = (typeof raw === 'string' ? raw.split(/\\s+/) : Array.isArray(raw) ? raw : [])\n    .map(f => f.replace(/^-/, ''))\n    .filter(f => ALLOWED_FIELDS.has(f));\n  return fields.length ? fields.join(' ') : undefined;\n}\nconst docs = await Model.find().select(buildProjection(req.query.fields));","typeGuard":"function isSelectArg(arg) {\n  return arg == null || typeof arg === 'string' || (typeof arg === 'object' && arg !== null);\n}","tryCatchPattern":"try {\n  query.select(projection);\n} catch (err) {\n  if (err instanceof TypeError && err.message.includes('select()')) {\n    throw new Error(`Invalid projection passed to select(): ${JSON.stringify(projection)}`);\n  }\n  throw err;\n}","preventionTips":["Whitelist user-supplied projection field names before passing them to select()","Type projections as string | Record<string, 1 | 0> in TypeScript","Never pass booleans or numbers to select(); use an explicit spec or omit the call"],"tags":["mongoose","query","projection","select","typeerror","invalid-argument"],"backgroundTag":"invalid-projection-argument","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}