affaan-m/ECC · error · FalError

download requires HTTPS on an approved fal.media host

Error message

download requires HTTPS on an approved fal.media host

What it means

FalError raised by _validate_download_url() when a download target URL is not HTTPS on an approved fal.media host (exact host 'fal.media' or any '*.fal.media' subdomain), or carries embedded credentials or a non-443 port. This guard is enforced both for the initial download URL and on every redirect (via _SafeRedirect), preventing the library from fetching attacker-controlled URLs or leaking data to non-approved hosts.

Solutions

  1. Use the exact URL returned by fal APIs unmodified — it should be https on fal.media
  2. Downgrade http:// to https:// only if the host is fal.media or *.fal.media
  3. Strip any embedded credentials or explicit port from the URL
  4. If the provider now returns a different host, update the allowlist in _validate_download_url consciously (with a security review) rather than bypassing it

Example fix

// before
url = result["video"]["url"].replace("https", "http")
download(url, dest)
// after
url = result["video"]["url"]  # https://...fal.media/...
download(url, dest)
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse
def is_approved_fal_url(u: str) -> bool:
    p = urlparse(u)
    return (p.scheme == "https" and not p.username and not p.password
            and p.port in (None, 443)
            and (p.hostname == "fal.media" or (p.hostname or "").endswith(".fal.media")))

Type guard

def is_approved_fal_url(u: object) -> bool:
    if not isinstance(u, str):
        return False
    try:
        p = urlparse(u)
    except ValueError:
        return False
    return p.scheme == "https" and p.hostname in ("fal.media",) or (p.hostname or "").endswith(".fal.media") and p.scheme == "https"

Try / catch

try:
    download(url, dest)
except FalError as e:
    if "approved fal.media host" in str(e):
        logging.error("refusing non-approved download URL: %r", safe_url(url))
    raise

Prevention

When it happens

Trigger: Passing an http:// URL, a non-fal.media host (CDN host other than fal.media), a URL with user:pass@, an explicit port like :8443, or a redirect chain that hops to a disallowed host.

Common situations: Provider responses that changed and now point at a different CDN domain; hand-editing URLs to http; older cached URLs pointing at a legacy host; a redirect from fal.media to a generic storage domain that the validator blocks by design.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/271bbe938b9dc4ea. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/falapi.py:671

# ---------------------------------------------------------------------------
# download
# ---------------------------------------------------------------------------


MAX_DOWNLOAD_BYTES = 2 * 1024 * 1024 * 1024  # bounded large video/GLB downloads


def _validate_download_url(url: str) -> None:
    try:
        parsed = urllib.parse.urlsplit(url)
        host = parsed.hostname or ""
        valid = (parsed.scheme == "https" and not parsed.username
                 and not parsed.password and parsed.port in (None, 443)
                 and (host == "fal.media" or host.endswith(".fal.media")))
    except ValueError:
        valid = False
    if not valid:
        raise FalError("download requires HTTPS on an approved fal.media host")


class _SafeRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        _validate_download_url(newurl)
        return super().redirect_request(req, fp, code, msg, headers, newurl)


def download(url: str, dest: str | Path) -> Path:
    """Bounded HTTPS download; failed transfers preserve existing destinations."""
    dest = Path(dest)
    if is_dry_run():
        dest.parent.mkdir(parents=True, exist_ok=True)
        dest.write_bytes(b"taste-forge dry-run placeholder\n")
        log.info("[dry-run] would download from %s", safe_url(url))
        return dest

    require_live()

View on GitHub (pinned to 8321021c54)