{"record":{"id":"b5c5035c534b2cb3","repo":"nodejs/node","slug":"invalid-maxttl-must-be-a-positive-number","errorCode":null,"errorMessage":"Invalid maxTTL. Must be a positive number","messagePattern":"Invalid maxTTL\\. Must be a positive number","errorType":"exception","errorClass":"InvalidArgumentError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/interceptor/dns.js","lineNumber":463,"sourceCode":"        break\n      }\n      case 'ENOTFOUND':\n        this.#state.deleteRecords(this.#origin)\n        super.onResponseError(controller, err)\n        break\n      default:\n        super.onResponseError(controller, err)\n        break\n    }\n  }\n}\n\nmodule.exports = interceptorOpts => {\n  if (\n    interceptorOpts?.maxTTL != null &&\n    (typeof interceptorOpts?.maxTTL !== 'number' || interceptorOpts?.maxTTL < 0)\n  ) {\n    throw new InvalidArgumentError('Invalid maxTTL. Must be a positive number')\n  }\n\n  if (\n    interceptorOpts?.maxItems != null &&\n    (typeof interceptorOpts?.maxItems !== 'number' ||\n      interceptorOpts?.maxItems < 1)\n  ) {\n    throw new InvalidArgumentError(\n      'Invalid maxItems. Must be a positive number and greater than zero'\n    )\n  }\n\n  if (\n    interceptorOpts?.affinity != null &&\n    interceptorOpts?.affinity !== 4 &&\n    interceptorOpts?.affinity !== 6\n  ) {\n    throw new InvalidArgumentError('Invalid affinity. Must be either 4 or 6')","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/interceptor/dns.js#L445-L481","documentation":"Thrown by the DNS interceptor's factory (an `InvalidArgumentError`, code `UND_ERR_INVALID_ARG`) when `maxTTL` is provided and is either not a number or is less than 0. The DNS interceptor caches resolved address records client-side to cut lookup latency; `maxTTL` (expressed in milliseconds, default 10000) caps how long a cached entry lives, overriding the record's own TTL when shorter. Note the code allows `0` despite the message saying 'positive' — only negatives and non-numbers are rejected.","triggerScenarios":"Passing `maxTTL` as a string (`'10000'`), a negative number, `NaN`, or an object. The guard checks `interceptorOpts?.maxTTL != null && (typeof !== 'number' || < 0)`, so `0` passes. Value is interpreted in milliseconds, not seconds.","commonSituations":"Configuring TTL in seconds while the library expects milliseconds (off by 1000×); reading TTL from env as a string; copying a value from a docs example that used seconds. The seconds-vs-milliseconds confusion is the dominant real-world cause.","solutions":["Pass `maxTTL` as a positive number in milliseconds, e.g. `maxTTL: 60_000` for one minute.","If your config uses seconds, convert: `maxTTL: ttlSeconds * 1000`.","Coerce env strings with `Number(...)` and validate finiteness before passing.","To disable caching expiry, omit `maxTTL` (default 10000 ms) rather than passing a sentinel."],"exampleFix":"// before\ninterceptor dns({ maxTTL: '60000' })       // string\ndns({ maxTTL: 60 })                          // seconds, far too short\ndns({ maxTTL: process.env.DNS_TTL })\n\n// after\ndns({ maxTTL: 60000 })                        // ms = 60s\ndns({ maxTTL: Number(process.env.DNS_TTL) })","handlingStrategy":"validation","validationCode":"function validateMaxTTL(v) {\n  if (v == null) return undefined\n  const n = Number(v)\n  if (typeof n !== 'number' || n < 0) {\n    throw new Error('maxTTL must be a non-negative number (milliseconds)')\n  }\n  return n // remember: milliseconds, not seconds\n}","typeGuard":"function isNonNegativeNumber(v) {\n  return typeof v === 'number' && v >= 0\n}","tryCatchPattern":null,"preventionTips":["Treat DNS maxTTL as milliseconds (default 10000).","Coerce env-provided TTLs with Number().","Convert seconds→ms at the config boundary."],"tags":["undici","interceptor","dns","cache","validation","config","units"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}