{"record":{"id":"2e673233109b50d8","repo":"denoland/deno","slug":"expected-highwatermark-to-be-a-positive-number-or","errorCode":null,"errorMessage":"Expected highWaterMark to be a positive number or Infinity, got \"${highWaterMark}\".","messagePattern":"Expected highWaterMark to be a positive number or Infinity, got \"(.+?)\"\\.","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":726,"sourceCode":"    throw new RangeError(\n      \"Cannot enqueue value with size: chunk size is invalid\",\n    );\n  }\n  container[_queue].enqueueWithSize(value, size);\n  container[_queueTotalSize] += size;\n}\n\n/**\n * @param {QueuingStrategy} strategy\n * @param {number} defaultHWM\n */\nfunction extractHighWaterMark(strategy, defaultHWM) {\n  if (strategy.highWaterMark === undefined) {\n    return defaultHWM;\n  }\n  const highWaterMark = strategy.highWaterMark;\n  if (NumberIsNaN(highWaterMark) || highWaterMark < 0) {\n    throw new RangeError(\n      `Expected highWaterMark to be a positive number or Infinity, got \"${highWaterMark}\".`,\n    );\n  }\n  return highWaterMark;\n}\n\n/**\n * Shared size algorithm for the default queuing strategy. Hot paths compare\n * against it by identity to skip the per-chunk call (and its try/catch).\n * @returns {number}\n */\nfunction defaultSizeAlgorithm() {\n  return 1;\n}\n\n/**\n * @template T\n * @param {QueuingStrategy<T>} strategy","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L708-L744","documentation":"extractHighWaterMark validates the highWaterMark field of any queuingStrategy passed to ReadableStream, WritableStream, and TransformStream constructors (ext/web/06_streams.js:720-731): undefined falls back to the constructor's default; NaN or any negative number throws RangeError 'Expected highWaterMark to be a positive number or Infinity, got ...'. Both 0 and Infinity are legal. Common triggers are the -1-as-'unlimited' idiom borrowed from other libraries, and NaN from computed or parsed configuration.","triggerScenarios":"new WritableStream(sink, { highWaterMark: -1 }); new TransformStream(t, { highWaterMark: NaN }); any strategy whose highWaterMark is computed as a negative number (e.g. limit * -1) or parsed from user config into NaN.","commonSituations":"Config-driven strategies where -1 is used to mean 'no limit' (other ecosystems allow it); NaN sneaking in through parseInt of bad input or undefined arithmetic; strategies copy-pasted between stream types with different defaults.","solutions":["Use a non-negative finite number or Infinity — replace the -1 'unlimited' idiom with Infinity.","Validate before constructing: if (Number.isNaN(hwm) || hwm < 0) throw a config error naming the source field.","When unsure, omit highWaterMark and rely on the constructor default.","Sanity-check parsed config: coerce with Number() first and reject NaN explicitly."],"exampleFix":"// before\nnew WritableStream(sink, { highWaterMark: -1 }); // RangeError\n\n// after\nnew WritableStream(sink, { highWaterMark: 1 }); // use Infinity for effectively-unbounded","handlingStrategy":"validation","validationCode":"const hwm = strategy.highWaterMark;\nif (hwm !== undefined && (Number.isNaN(hwm) || hwm < 0)) {\n  throw new RangeError(`bad highWaterMark: ${hwm}`);\n}\nconst stream = new WritableStream(sink, { highWaterMark: hwm ?? 1 });","typeGuard":"const isValidHWM = (n) =>\n  n === undefined || (typeof n === 'number' && !Number.isNaN(n) && n >= 0);","tryCatchPattern":"try {\n  stream = new ReadableStream(src, strategy);\n} catch (e) {\n  if (e instanceof RangeError && e.message.includes('highWaterMark')) {\n    stream = new ReadableStream(src, { highWaterMark: 1 });\n  } else throw e;\n}","preventionTips":["Use Infinity (never -1) for effectively-unbounded buffering","Validate config-sourced highWaterMark before constructing streams","Omit highWaterMark when the default is acceptable"],"tags":["streams","queuing-strategy","highwatermark","rangeerror"],"backgroundTag":"stream-queuing-strategy-invalid","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}