{"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/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/timeout.ts#L46-L82","documentation":"Thrown by the @internal Timeout class constructor when the requested duration is a negative number. Durations of 0 are allowed (used for immediately-rejecting timeouts), but negative durations are nonsensical and rejected up front. It is a MongoInvalidArgumentError.","triggerScenarios":"Driver internals computing a remaining time that goes negative (e.g. timeoutMS already exceeded before a Timeout.expires() call) and passing it to the constructor. Not reachable through the public API directly under normal use.","commonSituations":"CSOT (Client-Side Operation Timeout) edge cases where the deadline has already passed by the time a new Timeout is constructed; bugs in timeout arithmetic; race between timeout expiry and a new operation start.","solutions":["If you are a driver maintainer, clamp duration to 0 when negative before constructing a Timeout, or use Timeout.reject() to fail fast.","As a user, ensure timeoutMS values are non-negative and that you are not chaining operations after a timeout has already fired.","Upgrade the driver: many negative-duration paths were hardened in recent releases; check HISTORY.md."],"exampleFix":"// before (driver-internal pattern)\nreturn new Timeout(undefined, { duration: remaining - slack }); // remaining < slack -> throws\n\n// after\nconst dur = Math.max(0, remaining - slack);\nreturn dur === 0 ? Timeout.reject(new MongoOperationTimeoutError('expired')) : Timeout.expires(dur);","handlingStrategy":"validation","validationCode":"// internal: clamp durations before constructing a Timeout\nconst safeDuration = Math.max(0, requestedDuration);\nif (safeDuration === 0) {\n  return Timeout.reject(new MongoOperationTimeoutError('expired'));\n}\nreturn Timeout.expires(safeDuration);","typeGuard":"function isNonNegativeMs(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v >= 0;\n}","tryCatchPattern":null,"preventionTips":["Always pass non-negative millisecond values to timeout-related options (timeoutMS, socketTimeoutMS).","In driver internals, clamp computed durations to 0 before constructing Timeout.","Treat a computed negative duration as 'expired' and fail fast with Timeout.reject()."],"tags":["timeout","csot","internal","invalid-argument"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}