{"id":"fc238ff5f8a30185","repo":"sequelize/sequelize","slug":"the-argument-passed-to-findone-must-be-an-options","errorCode":null,"errorMessage":"The argument passed to findOne must be an options object, use findByPk if you wish to pass a single primary key value","messagePattern":"The argument passed to findOne must be an options object, use findByPk if you wish to pass a single primary key value","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/model.js","lineNumber":1570,"sourceCode":"        }\n      }),\n    );\n\n    return original;\n  }\n\n  /**\n   * Search for a single instance.\n   *\n   * Returns the first instance corresponding matching the query.\n   * If not found, returns null or throws an error if {@link FindOptions.rejectOnEmpty} is set.\n   *\n   * @param  {object}       [options] A hash of options to describe the scope of the search\n   * @returns {Promise<Model|null>}\n   */\n  static async findOne(options) {\n    if (options !== undefined && !isPlainObject(options)) {\n      throw new Error(\n        'The argument passed to findOne must be an options object, use findByPk if you wish to pass a single primary key value',\n      );\n    }\n\n    options = cloneDeep(options) ?? {};\n    // findOne only ever needs one result\n    // conditional temporarily fixes 14618\n    // https://github.com/sequelize/sequelize/issues/14618\n    if (options.limit === undefined) {\n      options.limit = 1;\n    }\n\n    // Bypass a possible overloaded findAll.\n    return await Model.findAll.call(\n      this,\n      defaultsLodash(options, {\n        model: this,\n        plain: true,","sourceCodeStart":1552,"sourceCodeEnd":1588,"githubUrl":"https://github.com/sequelize/sequelize/blob/7e1deec499d5afbb8d1877c2f4d545cead1214ec/packages/core/src/model.js#L1552-L1588","documentation":"Thrown by Model.findOne() when its single argument is defined but is not a plain object (e.g. a number, string, or array). findOne only accepts an options object; passing a primary key value is a common pre-v5 mistake that newer Sequelize rejects. To look up a row by its primary key you must call findByPk instead. The guard runs before any query is built, so no SQL is executed.","triggerScenarios":"Calling User.findOne(123), User.findOne('abc'), or User.findOne([1,2]). Also triggered by passing a Sequelize.literal() or any non-plain-object (class instance, Formidable form, etc.) as the only argument. Note: findOne(undefined) and findOne() are allowed.","commonSituations":"Upgrading from Sequelize v3/v4 where findOne accepted a plain PK number. Migrating from Mongoose whose findById semantics differ. Passing a value computed at runtime that is unexpectedly null-coerced to a number or that comes back as a wrapped type (e.g. BigNumber, ObjectId).","solutions":["Replace findOne(pkValue) with findByPk(pkValue) when you have a primary key.","Wrap the value in an options object: findOne({ where: { id: value } }).","Add a runtime guard that routes numbers/strings to findByPk and objects to findOne.","Audit call sites upgraded across major versions; the v5 upgrade guide lists this breaking change."],"exampleFix":"// before\nconst user = await User.findOne(42);\n\n// after\nconst user = await User.findByPk(42);\n// or\nconst user = await User.findOne({ where: { id: 42 } });","handlingStrategy":"validation","validationCode":"import { isPlainObject } from '@sequelize/core';\n\nfunction safeFindOne(Model, arg) {\n  if (arg === undefined) return Model.findOne();\n  if (typeof arg === 'number' || typeof arg === 'string' || Buffer.isBuffer(arg)) {\n    return Model.findByPk(arg);\n  }\n  if (!isPlainObject(arg)) {\n    throw new TypeError('findOne expects an options object or a PK for findByPk');\n  }\n  return Model.findOne(arg);\n}","typeGuard":"function isFindOneOptions(v): v is object {\n  return v === undefined || (typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Date) && !(v instanceof Buffer));\n}","tryCatchPattern":null,"preventionTips":["Never pass a raw primary key to findOne; route PKs through findByPk.","Lint for findOne(<literal number|string>) calls.","After a major-version upgrade, grep for findOne(\\d) and findOne('...')."],"tags":["api-misuse","query","findone","breaking-change"],"analyzedSha":"7e1deec499d5afbb8d1877c2f4d545cead1214ec","analyzedAt":"2026-08-03T18:58:44.549Z","schemaVersion":2}