{"id":"3f6aeabb02c8a9e0","repo":"mongodb/node-mongodb-native","slug":"an-operation-cannot-be-given-a-timeoutms-setting-w","errorCode":null,"errorMessage":"An operation cannot be given a timeoutMS setting when inside a withTransaction call that has a timeoutMS setting","messagePattern":"An operation cannot be given a timeoutMS setting when inside a withTransaction call that has a timeoutMS setting","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/utils.ts","lineNumber":551,"sourceCode":"            wtimeout: undefined,\n            wtimeoutMS: undefined\n          }\n        });\n      }\n      result.writeConcern = writeConcern;\n    }\n  }\n\n  result.timeoutMS = timeoutMS;\n\n  const readPreference = ReadPreference.fromOptions(options) ?? parent?.readPreference;\n  if (readPreference) {\n    result.readPreference = readPreference;\n  }\n\n  const isConvenientTransaction = session?.explicit && session?.timeoutContext != null;\n  if (isConvenientTransaction && options?.timeoutMS != null) {\n    throw new MongoInvalidArgumentError(\n      'An operation cannot be given a timeoutMS setting when inside a withTransaction call that has a timeoutMS setting'\n    );\n  }\n\n  return result;\n}\n\nexport function isSuperset(set: Set<any> | any[], subset: Set<any> | any[]): boolean {\n  set = Array.isArray(set) ? new Set(set) : set;\n  subset = Array.isArray(subset) ? new Set(subset) : subset;\n  for (const elem of subset) {\n    if (!set.has(elem)) {\n      return false;\n    }\n  }\n  return true;\n}\n","sourceCodeStart":533,"sourceCodeEnd":569,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/utils.ts#L533-L569","documentation":"Thrown by resolveOptions() when an operation is executed inside a 'convenient transaction' (a withTransaction() call that carries its own timeoutMS) AND the individual operation is also given a timeoutMS. The convenient-transaction API owns the timeout budget for the whole transaction, so a nested per-operation timeoutMS is contradictory and forbidden. It surfaces as a MongoInvalidArgumentError to prevent ambiguous/competing timeout semantics.","triggerScenarios":"Inside `session.withTransaction(async (session) => { ... }, { timeoutMS: 5000 })`, calling any operation with an explicit `{ timeoutMS: N }` option, e.g. `coll.findOne({}, { session, timeoutMS: 1000 })`.","commonSituations":"Copying an operation helper that hardcodes timeoutMS into a withTransaction callback; layering the new timeoutMS API (v6+) onto existing transaction code without removing per-call timeouts; shared option objects spread into both transactional and non-transactional calls.","solutions":["Remove the per-operation timeoutMS inside the withTransaction callback; let the transaction's timeoutMS govern.","If a specific operation needs a shorter bound, enforce it with your own Promise.race/AbortController instead of timeoutMS.","Audit shared option builders so timeoutMS is not spread into operations that run under withTransaction."],"exampleFix":"// before\nawait session.withTransaction(\n  async (session) => {\n    await coll.insertOne({ a: 1 }, { session, timeoutMS: 1000 }); // throws\n  },\n  { timeoutMS: 5000 }\n);\n\n// after\nawait session.withTransaction(\n  async (session) => {\n    await coll.insertOne({ a: 1 }, { session }); // no nested timeoutMS\n  },\n  { timeoutMS: 5000 }\n);","handlingStrategy":"validation","validationCode":"function stripTimeoutInsideTx<T extends { timeoutMS?: number; session?: ClientSession }>(opts: T | undefined): T {\n  if (opts?.session?.inTransaction() && opts.timeoutMS != null) {\n    const { timeoutMS, ...rest } = opts;\n    return rest as T;\n  }\n  return opts ?? ({} as T);\n}","typeGuard":"function isInsideConvenientTransaction(session?: ClientSession): boolean {\n  return !!session?.explicit && (session as any).timeoutContext != null;\n}","tryCatchPattern":null,"preventionTips":["Never pass timeoutMS to operations running inside withTransaction.","Keep transactional and non-transactional option objects separate.","Let the transaction-level timeoutMS own the budget."],"tags":["transactions","timeout","validation"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}