iflytek/astron-agent · error · HTTPClientException
HTTPClientError
HTTPClientError
Error message
{exc} What it means
fetch_public_resource is the SSRF-hardened remote-file downloader. When any of its internal policy checks (RemoteResourcePolicyError) reject the URL, address, redirect, or payload, the policy reason is surfaced as an HTTPClientException with code HTTPClientError and the reason appended via extra_message. This means the download was refused by the library's safety validation, not that the network failed.
Solutions
- Read extra_message (str(exc) from the wrapped RemoteResourcePolicyError) — it states the exact policy reason; fix the URL accordingly.
- Ensure the URL is a well-formed http(s) URL with hostname, no credentials, no fragment, and points at a public address.
- If the resource legitimately exceeds the limit, pass a larger max_bytes explicitly.
- For private object storage, use a URL under the configured OSS_DOWNLOAD_HOST origin/bucket so _is_configured_storage_url authorizes it (requires OSS_TYPE=s3).
Example fix
// before
await fetch_public_resource("ftp://files.example.com/report.pdf")
// after
await fetch_public_resource("https://files.example.com/report.pdf") Defensive patterns
Strategy: try-catch
Validate before calling
from urllib.parse import urlsplit
p = urlsplit(url)
assert url.startswith(("http://", "https://")) and p.hostname and "@" not in p.netloc and not p.fragment Type guard
def is_safe_url(u):
from urllib.parse import urlsplit
try:
p = urlsplit(u)
except ValueError:
return False
return isinstance(u, str) and p.scheme in ("http", "https") and bool(p.hostname) and "@" not in p.netloc Try / catch
try:
data = await fetch_public_resource(url)
except HTTPClientException as e:
log.warning("download rejected: %s", e)
return None Prevention
- Validate URLs are https with a public hostname at your API boundary
- Keep resources under the configured OSS origin to benefit from the private-storage exception
- Watch max_bytes against expected artifact sizes
When it happens
Trigger: Any RemoteResourcePolicyError raised inside fetch_public_resource: malformed URL, disallowed scheme, private/reserved target IP, user-info in URL, non-2xx status, oversized body, or invalid size limit (max_bytes <= 0). Callers include gen_params and req_ase_ability_ocr_service.
Common situations: Passing a file:// or ftp:// URL; pointing at localhost or an internal 10.x/192.168.x address; a URL containing user:pass@; a signed URL with a #fragment; a storage host that redirects (302) to a CDN; a file larger than the 50MB default limit.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- Remote resource URL authority is invalid
- Remote resource URL must not include a fragment
- Remote resource address is unsafe
- Skill resource URL is not allowed
- MODEL_URL_CHECK_FAILED
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/5278693aa1f13f9f.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/aitools/common/clients/safe_download.py:109
parsed, _ = _validate_resource_url(url)
hostname = _normalize_hostname(parsed.hostname or "")
connector = aiohttp.TCPConnector(
use_dns_cache=False,
socket_factory=create_public_socket_factory(url),
)
timeout = aiohttp.ClientTimeout(
total=_positive_float_setting(AIOHTTP_CLIENT_TOTAL_TIMEOUT_KEY, 300.0),
connect=_positive_float_setting(AIOHTTP_CLIENT_CONNECT_TIMEOUT_KEY, 10.0),
sock_read=_positive_float_setting(AIOHTTP_CLIENT_READ_TIMEOUT_KEY, 60.0),
)
return await _download_resource(url, connector, timeout, max_bytes)
except RemoteResourcePolicyError as exc:
log.warning(
"Remote resource download rejected, host={}, reason={}", hostname, exc
)
if span is not None:
span.add_error_event("Remote resource download rejected")
raise HTTPClientException.from_error_code(
CodeEnums.HTTPClientError,
extra_message=str(exc),
) from exc
except Exception as exc:
log.debug(
"Remote resource download failed, host={}, error_type={}",
hostname,
type(exc).__name__,
)
if span is not None:
span.add_error_event("Remote resource download failed")
raise HTTPClientException.from_error_code(
CodeEnums.HTTPClientError,
extra_message="Remote resource download failed",
) from exc
async def _download_resource(View on GitHub (pinned to 5e758547a8)