abi/screenshot-to-code · warning · ValueError
Unsupported protocol: {parsed.scheme}
Error message
Unsupported protocol: {parsed.scheme} What it means
ValueError("Unsupported protocol: {scheme}") raised by normalize_url() when urlparse assigns the URL a scheme that is not http/https and the fallback heuristics do not rescue it. The function auto-prefixes https:// for scheme-less inputs and for bare host:port strings, but explicitly refuses ftp://, file://, and anything else scheme-like (mailto:, javascript:, etc.). It is an input-rejection error, not an upstream failure.
Source
Thrown at backend/routes/screenshot.py:35
# Parse the URL
parsed = urlparse(url)
# Check if we have a scheme
if not parsed.scheme:
# No scheme, add https://
url = f"https://{url}"
elif parsed.scheme in ['http', 'https']:
# Valid scheme, keep as is
pass
else:
# Check if this might be a domain with port (like example.com:8080)
# urlparse treats this as scheme:netloc, but we want to handle it as domain:port
if ':' in url and not url.startswith(('http://', 'https://', 'ftp://', 'file://')):
# Likely a domain:port without protocol
url = f"https://{url}"
else:
# Invalid protocol
raise ValueError(f"Unsupported protocol: {parsed.scheme}")
return url
def bytes_to_data_url(image_bytes: bytes, mime_type: str) -> str:
base64_image = base64.b64encode(image_bytes).decode("utf-8")
return f"data:{mime_type};base64,{base64_image}"
async def capture_screenshot(
target_url: str, api_key: str, device: str = "desktop"
) -> bytes:
api_base_url = "https://api.screenshotone.com/take"
params = {
"access_key": api_key,
"url": target_url,
"full_page": "true",View on GitHub (pinned to d026163f58)
Solutions
- Pass an http:// or https:// URL, or a bare domain like example.com (the function adds https:// itself)
- If the target truly is ftp/file content, screenshotting is not supported — fetch the resource by another means
- Validate the scheme client-side before calling the endpoint
Example fix
# before url = "ftp://example.com" normalized = normalize_url(url) # ValueError # after url = "https://example.com" normalized = normalize_url(url) # ok
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
def is_screenshotable_url(url: str) -> bool:
p = urlparse(url)
if p.scheme in ("http", "https"):
return True
return p.scheme == "" and bool(p.netloc or p.path) # bare domain gets https:// prefixed Try / catch
try:
normalize_url(url)
except ValueError as e:
if str(e).startswith("Unsupported protocol"):
reject_input_to_user(url) # input problem, not a server fault Prevention
- Validate the scheme client-side before calling /api/screenshot
- Auto-prefix https:// in the UI for scheme-less input instead of sending raw paste
- Reject ftp://, file://, mailto:, javascript: early with a clear user message
When it happens
Trigger: POST /api/screenshot (or any caller of normalize_url) with url="ftp://example.com", url="file:///etc/passwd", or url="mailto:someone@example.com". Note "example.com:8080" does NOT trigger it — the host:port branch converts it to https://example.com:8080.
Common situations: Users paste an ftp:// or file:// link into the screenshot box; automated pipelines pass unvalidated URLs harvested from documents.
Related errors
- Unsupported model: {model.value}
- No stack was provided
- No model was provided
- Error capturing screenshot: {str(e)}
AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14).
Data as JSON: /api/errors/9296bb3b4128ecd9.
Report an issue: GitHub.