SeleniumHQ/selenium · error · ValueError

Download unavailable (HTTP {r.status}): {url}

Error message

Download unavailable (HTTP {r.status}): {url}

What it means

Raised by calculate_hash() in scripts/pinned_browsers.py when the HTTP GET to a browser/driver download URL returns a non-200 status. The function streams the response body (preload_content=False) to compute sha256, so it checks status before reading. This is a CI/build script used to pin browser binaries for the Selenium Bazel build (common/repositories.bzl).

Source

Thrown at scripts/pinned_browsers.py:26

import urllib3
from packaging.version import parse

from scripts.generated_note import generated_note

# Find the current stable versions of each browser we
# support and the sha256 of these. That's useful for
# updating `//common:repositories.bzl`

http = urllib3.PoolManager()


def calculate_hash(url):
    print(f"Calculate hash for {url}", file=sys.stderr)
    h = hashlib.sha256()
    r = http.request("GET", url, preload_content=False)
    if r.status != 200:
        raise ValueError(f"Download unavailable (HTTP {r.status}): {url}")
    for b in iter(lambda: r.read(4096), b""):
        h.update(b)
    return h.hexdigest()


def get_chrome_info_for_channel(channel):
    r = http.request(
        "GET",
        "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions.json",
    )
    milestone = json.loads(r.data)["channels"][channel]["version"].split(".")[0]
    r = http.request(
        "GET",
        "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json",
    )
    versions = json.loads(r.data)["versions"]

    return sorted(

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Retry the script — many failures are transient (CDN hiccups, rate limits).
  2. Check if the URL is reachable in a browser or with curl -I to distinguish 404 (permanent) from transient errors.
  3. If a vendor changed their URL scheme, update the pinned_browsers.py script to use the new URL pattern.
  4. Run the script from a network without proxies/firewalls that might block browser download endpoints.

Example fix

// before
$ bazel run //scripts:pinned_browsers
ValueError: Download unavailable (HTTP 404): https://...
// after
# Retry (transient):
$ bazel run //scripts:pinned_browsers
# If persistent, verify URL:
$ curl -I 'https://...'
Defensive patterns

Strategy: retry

Validate before calling

import urllib3
http = urllib3.PoolManager()
r = http.request('HEAD', url)
if r.status != 200:
    print(f'URL not available (HTTP {r.status}), deferring pinned_browsers run')
    # do not run the script

Type guard

null

Try / catch

try:
    calculate_hash(url)
except ValueError as e:
    # download unavailable; retry or report
    print(f'Skipping: {e}')

Prevention

When it happens

Trigger: Running the pinned_browsers.py script (via bazel run //scripts:pinned_browsers) when a download URL is temporarily or permanently unavailable: 404 (URL removed/changed), 403 (rate-limited or access denied), 500/502/503 (server error), or network connectivity issues during CI.

Common situations: Browser vendor (Google, Mozilla, Microsoft) temporarily takes down a download endpoint during a release transition; CDN rate limiting from too many CI runs; network proxy or firewall blocking the download; URL format changed upstream and the script has not been updated; transient network failure in CI.

Related errors


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/316a43a5a80e9b5b. Report an issue: GitHub.