commaai/openpilot · error · URLFileException

Expected 206 or 200 response {r.status} ({self._url})

Error message

Expected 206 or 200 response {r.status} ({self._url})

What it means

get_multi_range() issues an HTTP Range request and only accepts 200 (server ignored Range, sent everything) or 206 (partial content). Any other status — 403, 404, 416, 500 — raises immediately. 416 usually means seeking past EOF (bad cached length vs. truncated remote file).

Source

Thrown at openpilot/tools/lib/url_file.py:173

    if ll is None:
      length = self.get_length()
      if length == -1:
        raise URLFileException(f"Remote file is empty or doesn't exist: {self._url}")
      end = length
    else:
      end = self._pos + ll
    data = self.get_multi_range([(self._pos, end)])
    self._pos += len(data[0])
    return data[0]

  def get_multi_range(self, ranges: list[tuple[int, int]]) -> list[bytes]:
    # HTTP range requests are inclusive
    assert all(e > s for s, e in ranges), "Range end must be greater than start"
    rs = [f"{s}-{e-1}" for s, e in ranges if e > s]

    r = self._request("GET", self._url, headers={"Range": "bytes=" + ",".join(rs)})
    if r.status not in [200, 206]:
      raise URLFileException(f"Expected 206 or 200 response {r.status} ({self._url})")

    ctype = (r.headers.get("content-type") or "").lower()
    if "multipart/byteranges" not in ctype:
      return [r.data,]

    m = re.search(r'boundary="?([^";]+)"?', ctype)
    if not m:
      raise URLFileException(f"Missing multipart boundary ({self._url})")
    boundary = m.group(1).encode()

    parts = []
    for chunk in r.data.split(b"--" + boundary):
      if b"\r\n\r\n" not in chunk:
        continue
      payload = chunk.split(b"\r\n\r\n", 1)[1].rstrip(b"\r\n")
      if payload and payload != b"--":
        parts.append(payload)
    if len(parts) != len(ranges):

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Reproduce with curl -H 'Range: bytes=0-99' <url> to see the actual status
  2. Reset the URLFile length cache / recreate the URLFile so sizes are re-fetched, then retry
  3. If the link expired (403), obtain a fresh URL or re-authenticate

Example fix

# before
chunk = uf.get_multi_range([(0, 1024)])

# after
from openpilot.tools.lib.url_file import URLFileException
try:
    chunk = uf.get_multi_range([(0, 1024)])
except URLFileException as e:
    if '416' in str(e):
        uf._length = None  # stale cached length
        chunk = uf.get_multi_range([(0, 1024)])
    else:
        raise
Defensive patterns

Strategy: try-catch

Try / catch

from openpilot.tools.lib.url_file import URLFileException
try:
    parts = uf.get_multi_range(ranges)
except URLFileException as e:
    status = str(e).split()[3]
    if status == '416':
        uf._length = None  # stale size: refetch
        parts = uf.get_multi_range(ranges)
    else:
        raise

Prevention

When it happens

Trigger: Seeking/reading ranges from a URL whose server returns an error for ranged GET: file deleted mid-session, expired link (403), range beyond file size after the file changed, or a server that disallows ranges and errors instead of returning 200.

Common situations: Route file replaced/truncated on the backend while a cached length says it is longer; S3 presigned URL expired; proxy interfering with Range headers.

Related errors


AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15). Data as JSON: /api/errors/fa80096639325bcb. Report an issue: GitHub.