sgl-project/sglang · error · ValueError
Invalid media URL: {url!r}
Error message
Invalid media URL: {url!r} What it means
download_remote_media's URL gate (_assert_media_url_allowed) only accepts http/https URLs with a parseable hostname. FTP/data/file scheme URLs, or relative/garbage strings with no hostname, are rejected before any network request to prevent SSRF and unsupported-protocol issues.
Source
Thrown at python/sglang/srt/utils/common.py:1578
checks apply to image, video, audio, cache, and model-specific loaders.
"""
if max_file_size_mb < 0:
raise ValueError("media_url_max_file_size_mb must be non-negative")
normalized_domains = sorted(
{_normalize_media_domain(domain) for domain in allowed_media_domains or []}
)
global _allowed_media_domains, _media_url_max_file_size_bytes
_allowed_media_domains = frozenset(normalized_domains)
_media_url_max_file_size_bytes = max_file_size_mb * 1024 * 1024
return normalized_domains
def _assert_media_url_allowed(url: str) -> None:
parsed = urlparse(url)
if parsed.scheme not in {"http", "https"} or parsed.hostname is None:
raise ValueError(f"Invalid media URL: {url!r}")
hostname = _normalize_media_domain(parsed.hostname)
if _allowed_media_domains and hostname not in _allowed_media_domains:
raise ValueError(
"Media URL domain is not allowed. "
f"Allowed domains: {sorted(_allowed_media_domains)}; "
f"input domain: {hostname}"
)
def download_remote_media(url: str, timeout: float) -> bytes:
"""Download one HTTP(S) media object under the configured URL policy.
Redirects are followed manually so every destination is validated before
a connection is made. The response is streamed to enforce both the total
request deadline and the configured byte limit without first buffering an
attacker-controlled body in memory.
"""View on GitHub (pinned to 0132848349)
Solutions
- Handle local paths and base64/data URIs before calling download_remote_media
- Reject or URL-decode user input into the expected http(s) form client-side
- Keep the allowlist configured so accidental non-http inputs are caught
Example fix
# before
media = download_remote_media('data:image/png;base64,iVBOR...')
# after
if image.startswith('data:'): data = pybase64.b64decode(image.split(',', 1)[1])
else: data = download_remote_media(image) Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
p = urlparse(url)
assert p.scheme in ('http', 'https') and p.hostname, f'bad media url {url!r}'
data = download_remote_media(url, timeout=30) Type guard
def is_http_url(v) -> bool:
if not isinstance(v, str): return False
p = urlparse(v)
return p.scheme in {'http', 'https'} and p.hostname is not None Prevention
- Route data:/file:/base64 inputs through their dedicated paths first
- Reject non-http schemes at the request-validation layer
When it happens
Trigger: Passing 'ftp://x/file.png', 'file:///tmp/a.jpg', 'data:image/png;base64,...', or 'not-a-url' to download_remote_media (via fetch_image, preprocess_audio, load_audio, etc.) when it is not routed to a local/base64 path first.
Common situations: Multimodal pipelines forwarding arbitrary user-supplied strings to the remote downloader; base64 payloads not being detected earlier; clients sending file:// paths hoping to read server-local files (SSRF/LFI attempt).
Related errors
- allowed media domains must be strings
- Invalid allowed media domain {domain!r}: provide a hostname
- Invalid allowed media domain {domain!r}: ports are not suppo
- Media URL domain is not allowed. Allowed domains: {sorted(_a
- Invalid media URL: {current_url!r}
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/00b816b3e4a75dd2.
Report an issue: GitHub.