commaai/openpilot · error · ValueError

invalid wrapped firmware CRC

Error message

invalid wrapped firmware CRC

What it means

ValueError from validate_image(): the trailing 4 bytes of the file do not match zlib.crc32(body) computed over the firmware body. The CRC32 is the strongest of the wrapper's three integrity checks (length/magic, byte-sum, CRC32); a failure almost always means genuine data corruption rather than a format mistake.

Source

Thrown at openpilot/system/hardware/chestnut/flash.py:262

    self.write_buffer(data + bytes((-len(data)) % 4))
    self.write_enable()
    self.transaction(0x02, addr, len(data), mode=1)
    self.wait_write_done()


def validate_image(data):
  if len(data) < 10:
    raise ValueError("wrapped firmware is too short")
  body_len = int.from_bytes(data[:4], "little")
  if body_len > MAX_CODE_SIZE:
    raise ValueError(f"wrapped firmware body exceeds {MAX_CODE_SIZE} bytes")
  if len(data) != body_len + 10 or data[4 + body_len] != 0xA5:
    raise ValueError("invalid wrapped firmware length or magic")
  body = data[4:4 + body_len]
  if data[5 + body_len] != sum(body) & 0xFF:
    raise ValueError("invalid wrapped firmware checksum")
  if data[6 + body_len:] != zlib.crc32(body).to_bytes(4, "little"):
    raise ValueError("invalid wrapped firmware CRC")


def image_product(image):
  match = re.search(rb"custom [0-9a-f]{8}-CLEAN", image)
  if match is None:
    raise ValueError("no product string in wrapped firmware")
  return match.group().decode()


def reconnect(flash):
  attempt = 0
  while True:
    attempt += 1
    check_budget()
    try:
      flash.connect()
      flash.init()
      return

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Restore the artifact from a known-good source (CI artifact, version control) - do not attempt to fix the CRC bytes
  2. Fix the packaging script if you build wrappers: CRC must be zlib.crc32(body) only, little-endian, as the last 4 bytes
  3. Validate with an independent script before flashing so bad images never reach the device
  4. Check the storage medium if images corrupt repeatedly on the device
Defensive patterns

Strategy: validation

Validate before calling

import struct, zlib

def crc_ok(data: bytes) -> bool:
    if len(data) < 10:
        return False
    body_len = struct.unpack_from('<I', data)[0]
    if len(data) != body_len + 10:
        return False
    return data[6 + body_len:] == zlib.crc32(data[4:4 + body_len]).to_bytes(4, 'little')

Prevention

When it happens

Trigger: validate_image(data) where data[6+body_len:] != zlib.crc32(data[4:4+body_len]).to_bytes(4, 'little'). Any corruption of the body or CRC field that survived the weaker checks, or a wrapper built with a CRC over different bytes (e.g. including the header) or in big-endian order.

Common situations: Corrupted artifact on disk or in transit; a packaging script that CRCs the whole file instead of the body, or encodes the CRC big-endian; repeated corruption on flaky storage on the device itself.

Related errors


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