{"record":{"id":"7e2956d4b5afe652","repo":"crewAIInc/crewAI","slug":"max-bytes-must-be-positive-got-max-bytes","errorCode":null,"errorMessage":"max_bytes must be positive, got {max_bytes}.","messagePattern":"max_bytes must be positive, got (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/security/safe_requests.py","lineNumber":136,"sourceCode":"    Args:\n        url: The URL to fetch.\n        max_bytes: Largest body to accept, in decoded bytes.\n        timeout: Request timeout, passed through to requests.\n        headers: Request headers.\n        max_redirects: Hops to follow before giving up.\n\n    Returns:\n        A ``(body, content_type, final_url)`` tuple, where *final_url* is the\n        last validated URL in the redirect chain.\n\n    Raises:\n        ValueError: If *max_bytes* is not positive, URL validation fails, the\n            redirect chain is too long, or the body exceeds *max_bytes*.\n        requests.RequestException: If the request fails or returns an error\n            status.\n    \"\"\"\n    if max_bytes <= 0:\n        raise ValueError(f\"max_bytes must be positive, got {max_bytes}.\")\n\n    response = safe_get(\n        url,\n        max_redirects=max_redirects,\n        headers=headers,\n        timeout=timeout,\n        stream=True,\n    )\n    try:\n        response.raise_for_status()\n\n        chunks: list[bytes] = []\n        total = 0\n        for chunk in response.iter_content(chunk_size=_STREAM_CHUNK_SIZE):\n            if not chunk:\n                continue\n            total += len(chunk)\n            if total > max_bytes:","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/security/safe_requests.py#L118-L154","documentation":"Pure argument-validation error from fetch_url_body() in safe_requests.py: max_bytes must be a positive integer, and the function raises immediately (before any network I/O) when max_bytes <= 0. The limit exists so streamed bodies are capped; zero or negative caps are meaningless and rejected rather than silently disabling the cap.","triggerScenarios":"Calling fetch_url_body(url, max_bytes=0) hoping to mean 'unlimited'; passing a computed size that underflows to 0/negative (e.g. subtracting an offset larger than the base); a config default of 0 flowing into the parameter.","commonSituations":"Config files where the byte limit is left at 0 meaning 'not set'; arithmetic on chunk budgets; new callers assuming 0 disables the check.","solutions":["Pass an explicit positive byte limit, e.g. max_bytes=5_000_000 for ~5 MB.","If you intended 'unlimited', pick a large-but-finite sentinel (e.g. 1 GB) — the parameter is intentionally mandatory-positive.","Fix the upstream computation so it cannot produce <= 0 (clamp with max(1, value))."],"exampleFix":"# before\nbody, ctype, url = fetch_url_body(url, max_bytes=0)  # means 'unlimited' to caller\n\n# after\nbody, ctype, url = fetch_url_body(url, max_bytes=1_000_000_000)","handlingStrategy":"validation","validationCode":"max_bytes = max(1, int(max_bytes))  # clamp before calling\nassert max_bytes > 0","typeGuard":"def is_positive_int(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v > 0","tryCatchPattern":null,"preventionTips":["Never use 0 to mean 'unlimited' — this API has no unlimited mode; choose a large finite cap.","Validate numeric config values at load time, not at call time.","Clamp computed sizes with max(1, value) to survive subtraction edge cases."],"tags":["validation","api-misuse","limits"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}