{"record":{"id":"52d88c048662e284","repo":"commaai/openpilot","slug":"fn-is-empty","errorCode":null,"errorMessage":"{fn} is empty","messagePattern":"(.+?) is empty","errorType":"exception","errorClass":"DataUnreadableError","httpStatus":null,"severity":"error","filePath":"openpilot/tools/lib/framereader.py","lineNumber":40,"sourceCode":"    self.capacity = capacity\n\n  def __getitem__(self, key):\n    self._cache.move_to_end(key)\n    return self._cache[key]\n\n  def __setitem__(self, key, value):\n    self._cache[key] = value\n    if len(self._cache) > self.capacity:\n      self._cache.popitem(last=False)\n\n  def __contains__(self, key):\n    return key in self._cache\n\ndef assert_hvec(fn: str) -> None:\n  with FileReader(fn) as f:\n    header = f.read(4)\n  if len(header) == 0:\n    raise DataUnreadableError(f\"{fn} is empty\")\n  elif header == b\"\\x00\\x00\\x00\\x01\":\n    if 'hevc' not in fn:\n      raise NotImplementedError(fn)\n\ndef decompress_video_data(rawdat, w, h, pix_fmt=\"rgb24\", vid_fmt='hevc', hwaccel=\"auto\", loglevel=\"info\") -> np.ndarray:\n  threads = os.getenv(\"FFMPEG_THREADS\", \"0\")\n  args = [\"ffmpeg\", \"-v\", loglevel,\n          \"-threads\", threads,\n          \"-hwaccel\", hwaccel,\n          \"-c:v\", \"hevc\",\n          \"-vsync\", \"0\",\n          \"-f\", vid_fmt,\n          \"-flags2\", \"showall\",\n          \"-i\", \"pipe:0\",\n          \"-f\", \"rawvideo\",\n          \"-pix_fmt\", pix_fmt,\n          \"pipe:1\"]\n  dat = subprocess.check_output(args, input=rawdat)","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/tools/lib/framereader.py#L22-L58","documentation":"Thrown by assert_hvec() when the first 4 bytes of a video file read as zero-length. openpilot's framereader validates each camera file has a readable HEVC header before indexing; a truly empty (0-byte) file fails here. It surfaces as DataUnreadableError, the library's standard signal that route video data cannot be decoded.","triggerScenarios":"Calling FrameReader (or get_video_index/assert_hvec) on a route camera file whose size is 0 bytes — e.g. a truncated download from the API/cache, an incompletely uploaded segment, or a corrupted local file.","commonSituations":"Partial downloads in ~/.comma/... or the openpilot cache dir; a dashcam segment that failed to upload fully; pointing framereader at a placeholder or wrong path that happens to exist but is empty.","solutions":["Check the file size: ls -l <camera_file> — a 0-byte file is corrupt/truncated, re-download the segment or use another segment","Delete the cached copy and retry so it is re-fetched (cache lives under Paths.download_cache_root())","If reading locally, verify the original device data is intact (the upload itself was bad); use the qcamera stream as a fallback"],"exampleFix":"// before\nfr = FrameReader('https://useradmin.comma.ai/camera/...')\n\n// after\nimport os\nfrom openpilot.tools.lib.url_file import URLFile\n\nif URLFile(fn).get_length_online() <= 0:\n    print(f'{fn} is empty, skipping segment')\nelse:\n    fr = FrameReader(fn)","handlingStrategy":"validation","validationCode":"from openpilot.tools.lib.url_file import URLFile\n\ndef file_nonempty(fn: str) -> bool:\n    try:\n        return URLFile(fn).get_length_online() > 0 if fn.startswith('http') else os.path.getsize(fn) > 0\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"from openpilot.tools.lib.exceptions import DataUnreadableError\ntry:\n    fr = FrameReader(fn)\nexcept DataUnreadableError as e:\n    if 'is empty' in str(e):\n        skip_segment(fn)  # corrupt/truncated: do not retry","preventionTips":["Verify non-zero size before opening camera files in batch pipelines","Clear the download cache when a file unexpectedly reads empty so it is re-fetched","Treat empty camera files as segment-level failures and skip, not crash"],"tags":["video","corrupt-data","framereader","validation"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}