commaai/openpilot · error · URLFileException

Expected {len(ranges)} parts, got {len(parts)} ({self._url})

Error message

Expected {len(ranges)} parts, got {len(parts)} ({self._url})

What it means

After splitting a multipart/byteranges response by boundary, url_file counts the payload parts; if the count differs from the number of requested ranges it raises. Causes: server coalesced/dropped ranges, malformed boundaries causing over-splitting, or a 200 full-file response on a multipart content-type.

Source

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

    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):
      raise URLFileException(f"Expected {len(ranges)} parts, got {len(parts)} ({self._url})")
    return parts

  def seekable(self) -> bool:
    return True

  def seek(self, pos: int, whence: int = 0) -> int:
    pos = int(pos)
    if whence == os.SEEK_SET:
      self._pos = pos
    elif whence == os.SEEK_CUR:
      self._pos += pos
    elif whence == os.SEEK_END:
      length = self.get_length()
      assert length != -1, "Cannot seek from end on unknown length file"
      self._pos = length + pos
    else:
      raise URLFileException("Invalid whence value")
    return self._pos

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Fall back to one range per request (list of single-range calls) — most robust across servers
  2. Verify each requested range satisfies s<e and ranges don't overlap
  3. Compare raw response bytes with curl -H 'Range: bytes=0-1,5-6' to see what the server actually returns

Example fix

# before
parts = uf.get_multi_range(ranges)

# after
from openpilot.tools.lib.url_file import URLFileException
try:
    parts = uf.get_multi_range(ranges)
except URLFileException:
    parts = [uf.get_multi_range([r])[0] for r in ranges]
Defensive patterns

Strategy: fallback

Try / catch

try:
    parts = uf.get_multi_range(ranges)
except URLFileException as e:
    if 'parts, got' in str(e):
        parts = [uf.get_multi_range([r])[0] for r in ranges]

Prevention

When it happens

Trigger: get_multi_range() with N>1 ranges where the server returns fewer/more parts than requested, or boundary bytes appearing inside payload data causing spurious splits.

Common situations: Non-compliant proxies/CDNs rewriting ranged responses; overlapping or zero-width ranges after the e>s filter; servers that answer multi-range requests with only the first range.

Related errors


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