{"id":"bed84e3365b5b59c","repo":"mongodb/node-mongodb-native","slug":"cannot-set-timeoutmode-without-setting-timeoutms","errorCode":null,"errorMessage":"Cannot set timeoutMode without setting timeoutMS","messagePattern":"Cannot set timeoutMode without setting timeoutMS","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/cursor/abstract_cursor.ts","lineNumber":310,"sourceCode":"                'Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable awaitData cursor'\n              );\n          }\n\n          this.cursorOptions.timeoutMode = CursorTimeoutMode.ITERATION;\n        } else {\n          this.cursorOptions.timeoutMode = CursorTimeoutMode.LIFETIME;\n        }\n      } else {\n        if (options.tailable && options.timeoutMode === CursorTimeoutMode.LIFETIME) {\n          throw new MongoInvalidArgumentError(\n            \"Cannot set tailable cursor's timeoutMode to LIFETIME\"\n          );\n        }\n        this.cursorOptions.timeoutMode = options.timeoutMode;\n      }\n    } else {\n      if (options.timeoutMode != null)\n        throw new MongoInvalidArgumentError('Cannot set timeoutMode without setting timeoutMS');\n    }\n\n    // Set for initial command\n    this.cursorOptions.omitMaxTimeMS =\n      this.cursorOptions.timeoutMS != null &&\n      ((this.cursorOptions.timeoutMode === CursorTimeoutMode.ITERATION &&\n        !this.cursorOptions.tailable) ||\n        (this.cursorOptions.tailable && !this.cursorOptions.awaitData));\n\n    const readConcern = ReadConcern.fromOptions(options);\n    if (readConcern) {\n      this.cursorOptions.readConcern = readConcern;\n    }\n\n    if (typeof options.batchSize === 'number') {\n      this.cursorOptions.batchSize = options.batchSize;\n    }\n","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/cursor/abstract_cursor.ts#L292-L328","documentation":"Thrown when timeoutMode is set but timeoutMS is null/undefined. The timeoutMode option is only meaningful as a sub-property of CSOT (Client-Side Operation Timeout) and has no effect without a timeoutMS budget.","triggerScenarios":"Passing { timeoutMode: CursorTimeoutMode.LIFETIME } without a timeoutMS, or copying a config object that set timeoutMode but had timeoutMS stripped/overridden to undefined.","commonSituations":"Spreading a default-options object that includes timeoutMode then conditionally deleting timeoutMS; partial config from env where TIMEOUT_MS env var was unset.","solutions":["Always set timeoutMS when setting timeoutMode.","Remove timeoutMode if you are not using CSOT — the driver infers mode from timeoutMS presence.","Build options with a helper that sets both together or neither."],"exampleFix":"// before\ncollection.find(filter, { timeoutMode: CursorTimeoutMode.LIFETIME });\n// after\ncollection.find(filter, { timeoutMS: 5000, timeoutMode: CursorTimeoutMode.LIFETIME });","handlingStrategy":"validation","validationCode":"function checkModeHasTimeout(opts) {\n  if (opts.timeoutMode != null && opts.timeoutMS == null) return false;\n  return true;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat timeoutMode and timeoutMS as a pair — set both or neither.","Strip timeoutMode when conditionally removing timeoutMS (e.g. spread overrides).","Use a typed options builder that enforces the pairing."],"tags":["cursor","timeout","csot","options"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}