commaai/openpilot · error · VideoFileInvalid

slice_type must be 0, 1, or 2

Error message

slice_type must be 0, 1, or 2

What it means

Raised in get_hevc_slice_type() when the first ue(v) Exp-Golomb element of a slice segment header decodes to a value greater than 2. Per H.265 Table 7-7 only slice_type 0 (B), 1 (P), 2 (I) exist; all other values (3-9 are H.264-era repeat flags that HEVC removed) indicate the bit reader is misaligned — the stream is parsed at the wrong bit offset, usually due to a corrupt slice, wrong first-slice handling, or a file that is not HEVC.

Source

Thrown at openpilot/tools/lib/vidindex.py:258

  # in bitstreams conforming to this version of this Specification. Other values for num_extra_slice_header_bits are reserved
  # for future use by ITU-T | ISO/IEC. However, decoders shall allow num_extra_slice_header_bits to have any value.
  # TODO: get from PPS_NUT pic_parameter_set_rbsp( ) for corresponding slice_pic_parameter_set_id
  num_extra_slice_header_bits = 0
  skip_bits += num_extra_slice_header_bits

  # 7.4.7.1 General slice segment header semantics
  # slice_type specifies the coding type of the slice according to Table 7-7.
  # Table 7-7 - Name association to slice_type
  # slice_type | Name of slice_type
  #     0      | B (B slice)
  #     1      | P (P slice)
  #     2      | I (I slice)
  # unsigned integer 0-th order Exp-Golomb-coded syntax element with the left bit first
  slice_type, _ = get_ue(dat, rbsp_start, skip_bits)
  if DEBUG:
    print("  slice_type:", slice_type, f"(first slice: {is_first_slice})")
  if slice_type > 2:
    raise VideoFileInvalid("slice_type must be 0, 1, or 2")
  return slice_type, is_first_slice

def hevc_index(hevc_file_name: str, allow_corrupt: bool=False) -> tuple[list, int, bytes]:
  with FileReader(hevc_file_name) as f:
    dat = f.read()

  if len(dat) < NAL_UNIT_START_CODE_SIZE + 1:
    raise VideoFileInvalid("data is too short")

  if dat[0] != 0x00:
    raise VideoFileInvalid("first byte must be 0x00")

  prefix_dat = b""
  frame_types = []

  i = 1 # skip past first byte 0x00
  try:
    while i < len(dat):

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Retry with allow_corrupt=True — hevc_index wraps the parse loop so a bad slice can be skipped.
  2. Confirm the file is actually HEVC (check the SPS/parameter-set prefix data or run ffprobe) and not H.264 or an MP4 container.
  3. If one segment of a route fails, re-download it; cloud-stored segments are sometimes incomplete on first fetch.
  4. Inspect with an independent parser (ffprobe -show_frames) to confirm the file itself is damaged rather than a vidindex bug.

Example fix

# before
frames, prefix, prefix_dat = hevc_index(path)

# after
try:
    frames, prefix, prefix_dat = hevc_index(path)
except VideoFileInvalid:
    frames, prefix, prefix_dat = hevc_index(path, allow_corrupt=True)
Defensive patterns

Strategy: try-catch

Try / catch

try:
    frames, prefix, prefix_dat = hevc_index(path)
except VideoFileInvalid as e:
    if 'slice_type' in str(e):
        # bitstream desync: retry tolerating corruption, or re-fetch the segment
        frames, prefix, prefix_dat = hevc_index(path, allow_corrupt=True)
    else:
        raise

Prevention

When it happens

Trigger: hevc_index() reaches a NAL typed as a slice (VCL NAL unit) and get_ue() at rbsp_start + skip_bits returns > 2. Happens with bitstream corruption, when emulation-prevention bytes were removed/added incorrectly upstream, or when an H.264 stream is fed to the HEVC indexer.

Common situations: Corrupt dashboard-camera segments (SD card wear, interrupted writes), processing a renamed H.264 qcamera file through the HEVC path, or indexing partially-uploaded cloud routes. Sometimes a single bad frame in an otherwise good route.

Related errors


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