iflytek/astron-agent · error · RemoteResourcePolicyError
Remote resource URL must not include a fragment
Error message
Remote resource URL must not include a fragment
What it means
RemoteResourcePolicyError raised when the URL contains a fragment ('#...'). The SSRF-safe download module rejects fragments because a fragment is never sent to the server; keeping it could cause the validated URL and the actually-requested URL to differ (fragment delimiters can also be used to confuse parsers). The check fires in _validate_parsed_resource_url via parsed.fragment being truthy.
Solutions
- Strip the fragment before downloading: use urlsplit(url)._replace(fragment='').geturl() or URL(url).with_fragment(None)
- Validate/sanitize caller input to remove '#...' segments before invoking fetch_public_resource
- If the fragment carries meaning (e.g. PDF page), extract it separately and handle it in application code, not in the download URL
Example fix
// before
await fetch_public_resource("https://cdn.example.com/report.pdf#page=3")
// after
from urllib.parse import urlsplit, urlunsplit
parts = urlsplit(url)
clean = urlunsplit((parts.scheme, parts.netloc, parts.path, parts.query, ""))
await fetch_public_resource(clean) Defensive patterns
Strategy: validation
Validate before calling
def url_has_no_fragment(url: str) -> bool:
from urllib.parse import urlsplit
return not urlsplit(url).fragment Try / catch
try:
data = await fetch_public_resource(url)
except RemoteResourcePolicyError:
data = await fetch_public_resource(url.split('#', 1)[0]) Prevention
- Strip fragments from user-supplied URLs before downloading
- Never forward location.href (with hash) from frontends to download APIs
- Handle anchors (PDF pages, etc.) as separate application metadata
When it happens
Trigger: Calling fetch_public_resource(url) where url includes a '#fragment' suffix, e.g. 'https://cdn.example.com/file.pdf#page=3', or a caller-supplied URL copied from a browser address bar that retained an anchor.
Common situations: Users pasting browser URLs with anchors; document-processing pipelines that append '#page=N' to PDF links; frontend code forwarding full location.href (including hash) to a download API.
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
- HTTPClientError
- Remote resource URL authority is invalid
- Skill resource URL is not allowed
- MODEL_URL_CHECK_FAILED
- MODEL_URL_CHECK_FAILED
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/6a72d9fb3612c4bd.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/aitools/common/clients/safe_download.py:221
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"
)
if not parsed.hostname:
raise RemoteResourcePolicyError("Remote resource URL must include a hostname")
if parsed.username is not None or parsed.password is not None:
raise RemoteResourcePolicyError(
"Remote resource URL must not include user information"
)
if "\\" in parsed.netloc:
raise RemoteResourcePolicyError("Remote resource URL authority is invalid")
if parsed.fragment:
raise RemoteResourcePolicyError(
"Remote resource URL must not include a fragment"
)
if port is not None and not 1 <= port <= 65535:
raise RemoteResourcePolicyError("Remote resource URL port is invalid")
def _normalize_hostname(hostname: str) -> str:
value = hostname.strip().lower().rstrip(".")
if _parse_ip(value) is not None:
return value
try:
normalized = URL.build(scheme="http", host=value).raw_host
except (TypeError, ValueError, UnicodeError) as exc:
raise RemoteResourcePolicyError("Remote resource hostname is invalid") from exc
if not normalized:
raise RemoteResourcePolicyError("Remote resource hostname is invalid")
return normalized.rstrip(".")
View on GitHub (pinned to 5e758547a8)