{"record":{"id":"2e3da00361897f56","repo":"commaai/openpilot","slug":"remote-file-is-empty-or-doesn-t-exist-self-url","errorCode":null,"errorMessage":"Remote file is empty or doesn't exist: {self._url}","messagePattern":"Remote file is empty or doesn't exist: (.+?)","errorType":"exception","errorClass":"URLFileException","httpStatus":null,"severity":"error","filePath":"openpilot/tools/lib/url_file.py","lineNumber":158,"sourceCode":"        with atomic_write(full_path, mode=\"wb\", overwrite=True) as new_cached_file:\n          new_cached_file.write(data)\n        prune_cache(file_name)\n      else:\n        with open(full_path, \"rb\") as cached_file:\n          data = cached_file.read()\n\n      response += data[max(0, file_begin - position): min(CHUNK_SIZE, file_end - position)]\n\n      position += CHUNK_SIZE\n      if position >= file_end:\n        self._pos = file_end\n        return response\n\n  def read_aux(self, ll: int | None = None) -> bytes:\n    if ll is None:\n      length = self.get_length()\n      if length == -1:\n        raise URLFileException(f\"Remote file is empty or doesn't exist: {self._url}\")\n      end = length\n    else:\n      end = self._pos + ll\n    data = self.get_multi_range([(self._pos, end)])\n    self._pos += len(data[0])\n    return data[0]\n\n  def get_multi_range(self, ranges: list[tuple[int, int]]) -> list[bytes]:\n    # HTTP range requests are inclusive\n    assert all(e > s for s, e in ranges), \"Range end must be greater than start\"\n    rs = [f\"{s}-{e-1}\" for s, e in ranges if e > s]\n\n    r = self._request(\"GET\", self._url, headers={\"Range\": \"bytes=\" + \",\".join(rs)})\n    if r.status not in [200, 206]:\n      raise URLFileException(f\"Expected 206 or 200 response {r.status} ({self._url})\")\n\n    ctype = (r.headers.get(\"content-type\") or \"\").lower()\n    if \"multipart/byteranges\" not in ctype:","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/tools/lib/url_file.py#L140-L176","documentation":"read_aux() with no length argument needs the total file size; get_length() returns -1 when the server's HEAD gives no useful content-length or a non-2xx, and read_aux turns that into 'Remote file is empty or doesn't exist'. So either the URL 404s or the server refuses to report size.","triggerScenarios":"URLFile(url).read() (whole-file read) against a URL that returns 404/410, a pre-signed URL that expired, or a server that omits Content-Length on HEAD.","commonSituations":"Expired/rotated CDN links; route files purged from the backend; mis-pasted URL; servers behind config that strips HEAD handling.","solutions":["curl -I the URL to see the status and Content-Length","If the link is a presigned URL, regenerate it (they expire)","Read with an explicit byte length (read(ll)) if the size is known from elsewhere, avoiding the HEAD dependency"],"exampleFix":"# before\ndata = URLFile(url).read()\n\n# after\nuf = URLFile(url)\nlength = uf.get_length_online()\nif length <= 0:\n    raise FileNotFoundError(url)\ndata = uf.read(length)","handlingStrategy":"validation","validationCode":"length = URLFile(url).get_length_online()\nif length <= 0:\n    raise FileNotFoundError(url)  # or refresh the URL / skip","typeGuard":null,"tryCatchPattern":"from openpilot.tools.lib.url_file import URLFileException\ntry:\n    data = URLFile(url).read()\nexcept URLFileException as e:\n    if 'empty or doesn' in str(e):\n        url = refresh_presigned_url(url)  # expired link\n        data = URLFile(url).read()","preventionTips":["Check content length up front with get_length_online()","Regenerate presigned URLs rather than storing them long-term","Read with explicit length when the server's HEAD is unreliable"],"tags":["network","http","url-file","missing-files"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}