{"id":"41891d6f0c38ec6a","repo":"mongodb/node-mongodb-native","slug":"query-filter-must-be-a-plain-object-or-objectid","errorCode":null,"errorMessage":"Query filter must be a plain object or ObjectId","messagePattern":"Query filter must be a plain object or ObjectId","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/operations/find.ts","lineNumber":101,"sourceCode":"  /**\n   * @remarks WriteConcern can still be present on the options because\n   * we inherit options from the client/db/collection.  The\n   * key must be present on the options in order to delete it.\n   * This allows typescript to delete the key but will\n   * not allow a writeConcern to be assigned as a property on options.\n   */\n  override options: FindOptions & { writeConcern?: never };\n  filter: Document;\n\n  constructor(ns: MongoDBNamespace, filter: Document = {}, options: FindOptions = {}) {\n    super(undefined, options);\n\n    this.options = { ...options };\n    delete this.options.writeConcern;\n    this.ns = ns;\n\n    if (typeof filter !== 'object' || Array.isArray(filter)) {\n      throw new MongoInvalidArgumentError('Query filter must be a plain object or ObjectId');\n    }\n\n    // special case passing in an ObjectId as a filter\n    this.filter = filter != null && filter._bsontype === 'ObjectId' ? { _id: filter } : filter;\n\n    this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;\n  }\n\n  override get commandName() {\n    return 'find' as const;\n  }\n\n  override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {\n    return {\n      ...this.options,\n      ...this.bsonOptions,\n      documentsReturnedIn: 'firstBatch',\n      session: this.session,","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/operations/find.ts#L83-L119","documentation":"The FindOperation constructor (src/operations/find.ts:101) validates that the `filter` argument is a plain object (typeof 'object' and not an array). If a non-object or an array is passed, a MongoInvalidArgumentError is thrown before any server interaction. This is a client-side guard; the special case of passing an ObjectId is handled separately (it is wrapped into { _id: filter }).","triggerScenarios":"Calling collection.find('string'), collection.find(42), collection.find([1,2]), or collection.find(null) — any filter that is not a plain object or an ObjectId.","commonSituations":"Passing a value where a query document is expected — e.g. passing an ID string instead of {_id: id}, or passing an array of values hoping for an $in shorthand.","solutions":["Pass a plain object as the filter, e.g. collection.find({ status: 'active' }).","To query by _id, use collection.find({ _id: new ObjectId(id) }) or pass the ObjectId directly.","For multiple values, use $in: collection.find({ sku: { $in: ['a','b'] } })."],"exampleFix":"// before\nconst cursor = collection.find('abc'); // string, not an object\n\n// after\nconst cursor = collection.find({ name: 'abc' });\n// or by id:\nconst cursor = collection.find({ _id: new ObjectId('abc...') });","handlingStrategy":"type-guard","validationCode":"function isPlainObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n// usage before find:\nif (!isPlainObject(filter)) {\n  throw new TypeError('filter must be a plain object or ObjectId');\n}","typeGuard":"const isPlainObjectFilter = (f: unknown): boolean =>\n  (typeof f === 'object' && f !== null && !Array.isArray(f)) ||\n  (f != null && (f as any)._bsontype === 'ObjectId');","tryCatchPattern":null,"preventionTips":["Always pass a query document object to find(), never a bare value.","Use { _id: new ObjectId(id) } to query by identifier.","Enable TypeScript strict checks so non-object filters fail at compile time."],"tags":["argument-validation","find","filter","client-side"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}