{"record":{"id":"bca084a89a079ccf","repo":"iflytek/astron-agent","slug":"remote-resource-size-limit-is-invalid","errorCode":null,"errorMessage":"Remote resource size limit is invalid","messagePattern":"Remote resource size limit is invalid","errorType":"exception","errorClass":"RemoteResourcePolicyError","httpStatus":null,"severity":"error","filePath":"core/plugin/aitools/common/clients/safe_download.py","lineNumber":90,"sourceCode":"            address,\n            allow_private_storage=allow_private_storage,\n        )\n        return socket.socket(family=family, type=type_, proto=proto)\n\n    return socket_factory\n\n\nasync def fetch_public_resource(\n    url: str,\n    span: Optional[SpanLike] = None,\n    *,\n    max_bytes: int = DEFAULT_MAX_DOWNLOAD_BYTES,\n) -> bytes:\n    \"\"\"Download a public or exact trusted-storage resource with SSRF checks.\"\"\"\n    hostname = \"invalid\"\n    try:\n        if max_bytes <= 0:\n            raise RemoteResourcePolicyError(\"Remote resource size limit is invalid\")\n        parsed, _ = _validate_resource_url(url)\n        hostname = _normalize_hostname(parsed.hostname or \"\")\n        connector = aiohttp.TCPConnector(\n            use_dns_cache=False,\n            socket_factory=create_public_socket_factory(url),\n        )\n        timeout = aiohttp.ClientTimeout(\n            total=_positive_float_setting(AIOHTTP_CLIENT_TOTAL_TIMEOUT_KEY, 300.0),\n            connect=_positive_float_setting(AIOHTTP_CLIENT_CONNECT_TIMEOUT_KEY, 10.0),\n            sock_read=_positive_float_setting(AIOHTTP_CLIENT_READ_TIMEOUT_KEY, 60.0),\n        )\n        return await _download_resource(url, connector, timeout, max_bytes)\n    except RemoteResourcePolicyError as exc:\n        log.warning(\n            \"Remote resource download rejected, host={}, reason={}\", hostname, exc\n        )\n        if span is not None:\n            span.add_error_event(\"Remote resource download rejected\")","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/plugin/aitools/common/clients/safe_download.py#L72-L108","documentation":"fetch_public_resource() validates its max_bytes download budget before connecting: if max_bytes <= 0 the download policy is considered invalid and RemoteResourcePolicyError is raised immediately. It protects SSRF-hardened downloads from unbounded or nonsensical size limits.","triggerScenarios":"Calling fetch_public_resource(url, max_bytes=0), a negative value, or a max_bytes computed from an unvalidated config that yields <= 0.","commonSituations":"Config parsing returning 0 for an unset limit, integer parsing of an empty string, or a caller dividing the default limit incorrectly.","solutions":["Pass a positive max_bytes (e.g. DEFAULT_MAX_DOWNLOAD_BYTES)","Validate the size-limit config value at load time (must be > 0)","Fall back to the default when the configured limit is missing or invalid"],"exampleFix":"// before\nawait fetch_public_resource(url, max_bytes=int(os.getenv(\"MAX_DL\", \"\")))  # '' -> ValueError/0\n// after\nmax_bytes = int(os.getenv(\"MAX_DL\") or DEFAULT_MAX_DOWNLOAD_BYTES)\nif max_bytes <= 0: max_bytes = DEFAULT_MAX_DOWNLOAD_BYTES\nawait fetch_public_resource(url, max_bytes=max_bytes)","handlingStrategy":"validation","validationCode":"if not isinstance(max_bytes, int) or max_bytes <= 0:\n    max_bytes = DEFAULT_MAX_DOWNLOAD_BYTES","typeGuard":"def valid_download_limit(v) -> bool: return isinstance(v, int) and not isinstance(v, bool) and v > 0","tryCatchPattern":"try:\n    data = await fetch_public_resource(url, max_bytes=limit)\nexcept RemoteResourcePolicyError:\n    data = await fetch_public_resource(url)  # fall back to default limit","preventionTips":["Guard config-derived size limits (>0) at load time","Use int-or-default parsing for env vars (int(x or default))","Prefer the built-in DEFAULT_MAX_DOWNLOAD_BYTES unless a limit is explicitly required"],"tags":["download","security","validation"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}