{"record":{"id":"d083d37a9d7e3eff","repo":"mongodb/node-mongodb-native","slug":"cannot-create-a-timeout-with-a-negative-duration","errorCode":null,"errorMessage":"Cannot create a Timeout with a negative duration","messagePattern":"Cannot create a Timeout with a negative duration","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/timeout.ts","lineNumber":64,"sourceCode":"    if (this.duration === 0) return Infinity;\n    return this.start + this.duration - Math.trunc(performance.now());\n  }\n\n  get timeElapsed(): number {\n    return Math.trunc(performance.now()) - this.start;\n  }\n\n  /** Create a new timeout that expires in `duration` ms */\n  private constructor(\n    executor: Executor = () => null,\n    options?: { duration: number; unref?: true; rejection?: Error }\n  ) {\n    const duration = options?.duration ?? 0;\n    const unref = !!options?.unref;\n    const rejection = options?.rejection;\n\n    if (duration < 0) {\n      throw new MongoInvalidArgumentError('Cannot create a Timeout with a negative duration');\n    }\n\n    let reject!: Reject;\n    super((_, promiseReject) => {\n      reject = promiseReject;\n\n      executor(noop, promiseReject);\n    });\n\n    this.duration = duration;\n    this.start = Math.trunc(performance.now());\n\n    if (rejection == null && this.duration > 0) {\n      this.id = setTimeout(() => {\n        this.ended = Math.trunc(performance.now());\n        this.timedOut = true;\n        reject(new TimeoutError(`Expired after ${duration}ms`, { duration }));\n      }, this.duration);","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/timeout.ts#L46-L82","documentation":"Thrown by the internal Timeout constructor when the duration option is a negative number. Timeouts represent a finite future deadline, so a negative duration is logically invalid. The check guards every internal Timeout.expires() call that derives durations from user-supplied timeoutMS, socketTimeoutMS, serverSelectionTimeoutMS, etc.","triggerScenarios":"Setting a negative value for timeoutMS, socketTimeoutMS, waitQueueTimeoutMS, or serverSelectionTimeoutMS in MongoClientOptions or per-operation options. For example: new MongoClient(uri, { socketTimeoutMS: -100 }) or collection.findOne({}, { timeoutMS: -5 }).","commonSituations":"Configuration loaded from environment variables parsed incorrectly (e.g. Number('-1')), arithmetic bugs that subtract too much from a timeout budget, or copy-paste errors in connection string options like ?socketTimeoutMS=-1.","solutions":["Ensure all timeout options (timeoutMS, socketTimeoutMS, serverSelectionTimeoutMS, waitQueueTimeoutMS) are non-negative integers.","If timeouts come from env vars or config, validate them with a parseUnsignedInteger-style guard before passing to the client.","Use 0 or omit the option to disable a timeout rather than passing a negative number."],"exampleFix":"// before\nnew MongoClient(uri, { serverSelectionTimeoutMS: -1 });\n\n// after\nnew MongoClient(uri, { serverSelectionTimeoutMS: 5000 });","handlingStrategy":"validation","validationCode":"function resolveTimeout(name: string, value: unknown): number | undefined {\n  if (value == null) return undefined;\n  const n = typeof value === 'number' ? value : Number(value);\n  if (!Number.isFinite(n) || n < 0) throw new Error(`Invalid ${name}: ${value}`);\n  return Math.trunc(n);\n}\nnew MongoClient(uri, { serverSelectionTimeoutMS: resolveTimeout('serverSelectionTimeoutMS', process.env.SELECT_TIMEOUT) });","typeGuard":"function isNonNegativeNumber(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v >= 0;\n}","tryCatchPattern":"try {\n  await client.connect();\n} catch (e) {\n  if (e instanceof MongoInvalidArgumentError && /negative duration/.test(e.message)) {\n    // fix config and retry with valid timeouts\n  } else throw e;\n}","preventionTips":["Validate all timeout options from env/config with a non-negative-number guard before constructing the client.","Use 0 or omit a timeout to disable it instead of passing -1.","Centralize connection-string/option construction in one validated helper."],"tags":["timeout","configuration","validation"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}