iflytek/astron-agent · error · RemoteResourcePolicyError
Remote resource path is invalid
Error message
Remote resource path is invalid
What it means
RemoteResourcePolicyError raised by _decoded_path when the URL path cannot be safely decoded: it contains a malformed percent-escape (e.g. '%zz', a bare '%') or its percent-decoded bytes are not valid UTF-8. Used only by _is_configured_storage_url to compare the candidate path against configured S3 bucket prefixes, so a broken path also means private-storage authorization silently fails.
Solutions
- Percent-encode the path correctly: urllib.parse.quote(path, safe='/') with a known UTF-8 source string
- Re-upload or re-name the object with a UTF-8-safe filename and regenerate the URL
- Fix double-encoding in the URL-producing code (don't quote an already-quoted string)
Example fix
// before
url = f"https://s3.example.com/my-bucket/{filename}" # filename = '报告%进行中.pdf' (partially encoded)
// after
from urllib.parse import quote
url = f"https://s3.example.com/my-bucket/{quote(filename, safe='')}" Defensive patterns
Strategy: validation
Validate before calling
import re
from urllib.parse import unquote_to_bytes
INVALID_ESCAPE = re.compile(r"%(?![0-9a-fA-F]{2})")
def path_decodes_cleanly(url: str) -> bool:
raw = url.split("?", 1)[0]
if INVALID_ESCAPE.search(raw):
return False
try:
raw_path = raw.split("://", 1)[-1].split("/", 1)
path = "/" + raw_path[1] if len(raw_path) > 1 else "/"
unquote_to_bytes(path).decode("utf-8")
except (UnicodeDecodeError, ValueError):
return False
return True Try / catch
try:
data = await fetch_public_resource(url)
except HTTPClientException as e:
if "path is invalid" in str(e):
log.warning("Storage URL path has invalid percent-encoding or non-UTF-8 bytes")
raise Prevention
- Always percent-encode paths with urllib.parse.quote(value, safe='/') from UTF-8 source strings
- Convert non-UTF-8 filenames (GBK etc.) to UTF-8 before encoding into URLs
- Avoid double-encoding; never quote an already-quoted string
When it happens
Trigger: A candidate storage URL whose path contains invalid percent-encoding ('/my-bucket/file%.pdf') or percent-encoded bytes that don't form UTF-8 ('/my-bucket/%FF%FE.txt'), evaluated during private-storage authorization.
Common situations: Filenames uploaded with non-UTF-8 (e.g. GBK) encodings then blindly percent-encoded into URLs; double-encoding bugs producing stray '%' characters; copy-pasted URLs truncated mid-escape.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- HTTPClientError
- Remote resource URL authority is invalid
- Remote resource URL must not include a fragment
- Remote resource URL port is invalid
- Remote resource hostname is invalid
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/18b6b39fecfc3d7e.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/aitools/common/clients/safe_download.py:323
required_prefix
):
return True
return False
def _effective_port(parsed: SplitResult) -> int:
if parsed.port is not None:
return parsed.port
return 443 if parsed.scheme.lower() == "https" else 80
def _decoded_path(raw_path: str) -> str:
try:
if _INVALID_PERCENT_ESCAPE.search(raw_path):
raise ValueError
value = unquote_to_bytes(raw_path).decode("utf-8", errors="strict")
except (UnicodeDecodeError, ValueError):
raise RemoteResourcePolicyError("Remote resource path is invalid") from None
if (
not value.startswith("/")
or "\\" in value
or any(ord(character) < 0x20 or ord(character) == 0x7F for character in value)
or any(segment in {".", ".."} for segment in value.split("/"))
):
raise RemoteResourcePolicyError("Remote resource path is invalid")
return value
def _canonical_address(address: IpAddress) -> IpAddress:
if isinstance(address, ipaddress.IPv6Address) and address.ipv4_mapped:
return address.ipv4_mapped
return address
def _matches_any(address: IpAddress, networks: Tuple[IpNetwork, ...]) -> bool:
candidates: Tuple[IpAddress, ...] = (address,)View on GitHub (pinned to 5e758547a8)