iflytek/astron-agent · error · RemoteResourcePolicyError

Remote resource URL is malformed

Error message

Remote resource URL is malformed

What it means

_parse_resource_url wraps urllib.parse.urlsplit and the parsed.port property access; a TypeError or ValueError there (unparseable URL, invalid port, bad IPv6 literal) is converted to RemoteResourcePolicyError('Remote resource URL is malformed'). The library refuses to even evaluate policy on URLs it cannot parse deterministically.

Solutions

  1. Print/inspect the exact URL string being passed; look for truncation, unformatted placeholders, or stray characters.
  2. Validate the URL with urllib.parse.urlsplit plus a try/except around .port before sending it.
  3. URL-encode path/query components (urllib.parse.quote) instead of embedding raw special characters.
  4. Ensure the URL includes scheme and host, e.g. 'https://host/path', not a bare path or hostname.

Example fix

// before
url = f"https://host:{port}/file"  # port accidentally 'abc'
// after
url = f"https://host:{int(port)}/file"  # validated numeric port
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlsplit
try:
    p = urlsplit(url); _ = p.port
except ValueError:
    raise ValueError("malformed URL")

Type guard

def is_parseable_url(u):
    from urllib.parse import urlsplit
    if not isinstance(u, str):
        return False
    try:
        urlsplit(u).port
        return True
    except (TypeError, ValueError):
        return False

Try / catch

try:
    data = await fetch_public_resource(url)
except HTTPClientException as e:
    if "malformed" in str(e):
        ...  # return 400 to the caller

Prevention

When it happens

Trigger: urlsplit raises on inputs like 'http://[::1' (unclosed bracket) or 'http://host:port' (non-numeric port); parsed.port raises ValueError for out-of-range ports like ':99999'; url is not a string-convertible value (TypeError).

Common situations: User-supplied URL with typos ('htp:/example.com', missing scheme/host); template strings left unformatted ('{file_url}'); port concatenation bugs (f-string building ':{}' with a bad value); hostnames with unencoded characters.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/7418d590de921f48. Report an issue: GitHub.

Appendix: source

Thrown at core/plugin/aitools/common/clients/safe_download.py:192

def _positive_float_setting(name: str, default: float) -> float:
    try:
        value = float(os.getenv(name, str(default)))
    except (TypeError, ValueError):
        return default
    return value if math.isfinite(value) and value > 0 else default


def _parse_resource_url(url: str) -> SplitResult:
    _validate_url_characters(url)
    try:
        # ``urlsplit`` deliberately keeps semicolon path parameters in ``path``.
        # Dropping them would let policy validation inspect a different path from
        # the one aiohttp sends to the object-storage origin.
        parsed = urlsplit(url)
        port = parsed.port
    except (TypeError, ValueError) as exc:
        raise RemoteResourcePolicyError("Remote resource URL is malformed") from exc
    _validate_parsed_resource_url(parsed, port)
    return parsed


def _validate_url_characters(url: str) -> None:
    if not isinstance(url, str) or any(
        ord(character) < 0x20 or ord(character) == 0x7F for character in url
    ):
        raise RemoteResourcePolicyError("Remote resource URL is malformed")


def _validate_parsed_resource_url(
    parsed: SplitResult,
    port: Optional[int],
) -> None:
    if parsed.scheme.lower() not in _ALLOWED_SCHEMES:
        raise RemoteResourcePolicyError(
            "Only HTTP and HTTPS remote resources are allowed"

View on GitHub (pinned to 5e758547a8)