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()
returnView on GitHub (pinned to 516ec1e682)
Solutions
- Restore the artifact from a known-good source (CI artifact, version control) - do not attempt to fix the CRC bytes
- Fix the packaging script if you build wrappers: CRC must be zlib.crc32(body) only, little-endian, as the last 4 bytes
- Validate with an independent script before flashing so bad images never reach the device
- 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
- Match CRC scope exactly: body only, little-endian, last 4 bytes
- Treat any integrity failure as corruption - always re-fetch rather than repair
- Integrate validate_image() into CI so bad wrappers never ship
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
- invalid wrapped firmware length or magic
- invalid wrapped firmware checksum
- invalid config backup: {backup}
- expected one chestnut, found {len(found)}
- wrapped firmware is too short
AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15).
Data as JSON: /api/errors/bcd4f6e48a5036d1.
Report an issue: GitHub.