{"record":{"id":"7d15aa42a1da3619","repo":"pydantic/monty","slug":"maxbytes-must-be-a-finite-non-negative-number-or-null","errorCode":null,"errorMessage":"maxBytes must be a finite non-negative number or null","messagePattern":"maxBytes must be a finite non-negative number or null","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/monty-js/ts/print.ts","lineNumber":48,"sourceCode":" * Package-internal — do not re-export from index/node/wasm.\n */\nfunction checkPrintCollectLimit(current: number, add: number, maxBytes: number | null): void {\n  if (maxBytes === null) return\n  // Caps stay far below Number.MAX_SAFE_INTEGER; plain + is exact for our sizes.\n  const used = current + add\n  if (used > maxBytes) {\n    throw new MontyRuntimeError('MemoryError', `memory limit exceeded: ${used} bytes > ${maxBytes} bytes`)\n  }\n}\n\n/**\n * Normalize constructor `maxBytes`: only `null` disables the cap.\n * Rejects NaN/Infinity (which would make `used > maxBytes` never true) and negatives.\n */\nfunction resolveMaxBytes(maxBytes: number | null): number | null {\n  if (maxBytes === null) return null\n  if (typeof maxBytes !== 'number' || !Number.isFinite(maxBytes) || maxBytes < 0) {\n    throw new TypeError('maxBytes must be a finite non-negative number or null')\n  }\n  return maxBytes\n}\n\n/**\n * Accumulates print fragments into one string. Pass as `printCallback`.\n * Default cap: DEFAULT_MAX_PRINT_COLLECT_BYTES. Pass maxBytes: null to disable.\n * Host-side only — not covered by ResourceLimits.maxMemory.\n *\n * `maxBytes` must be a finite non-negative number or `null` (validated at construction).\n */\nexport class CollectString {\n  private buf = ''\n  private collectedBytes = 0\n  private readonly maxBytes: number | null\n\n  constructor(maxBytes: number | null = DEFAULT_MAX_PRINT_COLLECT_BYTES) {\n    this.maxBytes = resolveMaxBytes(maxBytes)","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-js/ts/print.ts#L30-L66","documentation":"The print collector's constructor `maxBytes` must be `null` (cap disabled) or a finite non-negative number. `NaN`/`Infinity` would make the `used > maxBytes` comparison never trip (silently disabling the cap) and negatives are meaningless, so a `TypeError` is thrown at construction time.","triggerScenarios":"`new PrintCollector({ maxBytes: Infinity })` intending 'unlimited', a NaN from a failed `parseFloat` of config, or a negative number.","commonSituations":"Using `Infinity` as an 'unlimited' sentinel; unvalidated env/JSON config parsed to NaN; a `-1` sentinel for 'no limit'.","solutions":["Pass `null` to disable the cap — not `Infinity` or `-1`","Validate numeric config before construction: `Number.isFinite(v) && v >= 0`","Coerce config with `Number(v)` and check for NaN before use"],"exampleFix":"// before\nconst collector = new PrintCollector({ maxBytes: Infinity })\n// after\nconst collector = new PrintCollector({ maxBytes: null }) // disable cap","handlingStrategy":"validation","validationCode":"if (maxBytes !== null && (typeof maxBytes !== 'number' || !Number.isFinite(maxBytes) || maxBytes < 0)) {\n  throw new Error(`invalid maxBytes: ${maxBytes}`)\n}","typeGuard":"function isValidMaxBytes(v: unknown): v is number | null {\n  return v === null || (typeof v === 'number' && Number.isFinite(v) && v >= 0)\n}","tryCatchPattern":"try {\n  const collector = new PrintCollector({ maxBytes })\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('maxBytes')) {\n    const collector = new PrintCollector({ maxBytes: null })\n  } else throw e\n}","preventionTips":["Use `null` (not `Infinity`) to disable the cap","Coerce and validate env/JSON config numbers before constructing","Check `Number.isFinite` whenever a value can be NaN (failed parse, 0/0)"],"tags":["typescript","constructor-validation","types"],"backgroundTag":"invalid-config-value","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}