Graphify-Labs/graphify · error · ValueError

Blocked URL scheme '{parsed.scheme}' - only http and https a

Error message

Blocked URL scheme '{parsed.scheme}' - only http and https are allowed. Got: {url!r}

What it means

ValueError from validate_url (security.py) when the URL's scheme is not http/https. This is the first tier of graphify's SSRF protection: file://, ftp://, data:, gopher: and everything else is rejected before any DNS or connection work, with the offending URL echoed.

Source

Thrown at graphify/security.py:113

        ip.is_private
        or ip.is_reserved
        or ip.is_loopback
        or ip.is_link_local
        or ip in _CGN_NETWORK
    )


def validate_url(url: str) -> str:
    """Raise ValueError if *url* is not http or https, or targets a private/internal IP.

    Blocks file://, ftp://, data:, and any other scheme that could be used
    for SSRF or local file access. Also blocks requests to private/reserved
    IP ranges (127.x, 10.x, 169.254.x, etc.) and cloud metadata endpoints
    to prevent SSRF in cloud environments.
    """
    parsed = urllib.parse.urlparse(url)
    if parsed.scheme.lower() not in _ALLOWED_SCHEMES:
        raise ValueError(
            f"Blocked URL scheme '{parsed.scheme}' - only http and https are allowed. "
            f"Got: {url!r}"
        )

    hostname = parsed.hostname
    if hostname:
        # Block known cloud metadata hostnames
        if hostname.lower() in _BLOCKED_HOSTS:
            raise ValueError(
                f"Blocked cloud metadata endpoint '{hostname}'. "
                f"Got: {url!r}"
            )

        # Resolve hostname and block private/reserved IP ranges
        try:
            infos = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM)
            for info in infos:
                addr = info[4][0]

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. Normalize input: if no scheme, deliberately prepend 'https://' before validation - but never blanket-append schemes to untrusted input without review.
  2. If the file is genuinely local, use local-file APIs instead of the URL fetcher - the block is intentional.
  3. Reject early in your own UI/config layer with a clear message so users fix the URL at entry time.

Example fix

# before
url = request.form['url']          # user sent 'example.com/page'
validate_url(url)                   # ValueError: Blocked URL scheme ''

# after - require an explicit scheme, default deliberately
url = request.form['url'].strip()
if '://' not in url:
    url = 'https://' + url          # only if defaulting is acceptable for your app
url = validate_url(url)
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def has_allowed_scheme(url: str) -> bool:
    return urlparse(url).scheme.lower() in ("http", "https")

if not has_allowed_scheme(url):
    raise HTTPBadRequest("URL must start with http:// or https://")

Type guard

def is_safe_url(url: str) -> bool:
    try:
        validate_url(url)
        return True
    except ValueError:
        return False

Try / catch

try:
    safe = validate_url(url)
except ValueError as exc:
    if "Blocked URL scheme" in str(exc):
        return bad_request(str(exc))  # user error - surface, do not log as 500
    raise

Prevention

When it happens

Trigger: validate_url(url) where urllib.parse.urlparse reports a scheme outside _ALLOWED_SCHEMES (security.py:110-115) - e.g. 'file:///etc/passwd', 'ftp://host/x', 'data:text/html,...', or a scheme-less 'example.com/path' (parsed scheme ''), which also fails since '' is not allowed.

Common situations: User-supplied URLs from tickets/config passed unchecked; copy-paste of paths without the https:// prefix; attempts to point fetchers at local files; protocol-handler confusion from frontend forms that strip the scheme.

Related errors


AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14). Data as JSON: /api/errors/723914c6273ceadf. Report an issue: GitHub.