{"record":{"id":"82c90bd483937681","repo":"ComposioHQ/composio","slug":"maxbytes-must-be-a-non-negative-safe-integer","errorCode":null,"errorMessage":"maxBytes must be a non-negative safe integer","messagePattern":"maxBytes must be a non-negative safe integer","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"ts/packages/core/src/utils/readResponseBody.ts","lineNumber":18,"sourceCode":"/** Maximum size accepted for files fetched from user-supplied URLs (100 MiB). */\nexport const MAX_URL_UPLOAD_SIZE_BYTES = 100 * 1024 * 1024;\n\nconst sizeLimitError = (actualSize: number, maxBytes: number): Error =>\n  new Error(`File size (${actualSize} bytes) exceeds maximum allowed size (${maxBytes} bytes)`);\n\n/**\n * Read a fetch response without allowing an untrusted server to exhaust memory.\n *\n * `Content-Length` is checked as an early rejection, but the streamed byte\n * count is authoritative because the header can be absent or dishonest.\n */\nexport const readResponseBodyWithLimit = async (\n  response: Response,\n  maxBytes: number = MAX_URL_UPLOAD_SIZE_BYTES\n): Promise<Uint8Array> => {\n  if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {\n    throw new RangeError('maxBytes must be a non-negative safe integer');\n  }\n\n  const contentLength = response.headers.get('content-length')?.trim();\n  if (contentLength && /^\\d+$/.test(contentLength)) {\n    const declaredSize = Number(contentLength);\n    if (!Number.isSafeInteger(declaredSize) || declaredSize > maxBytes) {\n      const error = sizeLimitError(declaredSize, maxBytes);\n      await response.body?.cancel(error).catch(() => undefined);\n      throw error;\n    }\n  }\n\n  if (!response.body) {\n    return new Uint8Array();\n  }\n\n  const reader = response.body.getReader();\n  const chunks: Uint8Array[] = [];","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/core/src/utils/readResponseBody.ts#L1-L36","documentation":"readResponseBodyWithLimit reads a fetch body with a byte cap (default 100 MiB for URL uploads). It validates its maxBytes argument and throws a RangeError when it is negative, fractional, NaN, Infinity, or beyond the safe-integer range.","triggerScenarios":"Calling readResponseBodyWithLimit(response, maxBytes) with a computed/derived limit that is negative, a float (e.g. 1.5 * 1024 * 1024), NaN, or Infinity — commonly from a config value parsed incorrectly or a default like Number.MAX_VALUE.","commonSituations":"Passing Infinity intending 'no limit'; parsing a size string like '10MB' into NaN; a subtraction underflowing to a negative number; passing a value from unvalidated user input.","solutions":["Pass an explicit, validated integer byte limit (e.g. 10 * 1024 * 1024)","Use Number.isSafeInteger + non-negative check on any computed limit before calling","For 'unlimited', pass a large safe integer instead of Infinity"],"exampleFix":"// before\nawait readResponseBodyWithLimit(res, Infinity);\n\n// after\nconst MAX = 100 * 1024 * 1024; // explicit cap\nawait readResponseBodyWithLimit(res, MAX);","handlingStrategy":"validation","validationCode":"if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {\n  throw new Error(`Bad maxBytes: ${maxBytes}`);\n}","typeGuard":"const isValidLimit = (n: unknown): n is number =>\n  typeof n === 'number' && Number.isSafeInteger(n) && n >= 0;","tryCatchPattern":"try {\n  await readResponseBodyWithLimit(res, limit);\n} catch (e) {\n  if (e instanceof RangeError) {\n    // fix the limit computation, don't retry\n  }\n}","preventionTips":["Never pass Infinity as a limit; choose an explicit integer cap","Validate size config values at load time with Number.isSafeInteger","Unit-test limit computation with edge inputs (0, floats, NaN)"],"tags":["validation","range-error","file-upload","typescript"],"backgroundTag":"invalid-argument-value","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}