commaai/openpilot · error · ValueError

wrapped firmware body exceeds {MAX_CODE_SIZE} bytes

Error message

wrapped firmware body exceeds {MAX_CODE_SIZE} bytes

What it means

ValueError from validate_image(): the 4-byte little-endian length header at the start of the wrapped image declares a body larger than MAX_CODE_SIZE (0x10000 = 65536 bytes), the capacity of the ASM2464 code region in SPI flash. The flasher refuses to attempt a write that cannot fit.

Source

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

  def erase_sector(self, addr):
    self.write_enable()
    self.transaction(0x20, addr)
    self.wait_write_done()

  def program(self, addr, data):
    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

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Confirm the file is the correct artifact: it must be the wrapped chestnut image produced by the matching build step, not a raw binary
  2. If building your own: reduce firmware size below 64KB (strip, optimize for size, remove dead code) and re-wrap with a correct header
  3. If hand-wrapping, write the header as struct.pack('<I', len(body)) and verify against the validate_image logic
  4. Check for accidental concatenation or prepended garbage that shifts the header

Example fix

# after (correct wrap)
body = open('fw.bin','rb').read()
assert len(body) <= 0x10000
wrapped = struct.pack('<I', len(body)) + body + b'\xa5' + bytes([sum(body) & 0xFF]) + zlib.crc32(body).to_bytes(4, 'little')
Defensive patterns

Strategy: validation

Validate before calling

import struct

def body_len_ok(data: bytes) -> bool:
    return len(data) >= 4 and struct.unpack_from('<I', data)[0] <= 0x10000

Try / catch

try:
    validate_image(data)
except ValueError as e:
    if 'exceeds' in str(e):
        fail_build('firmware too large - trim before flashing')

Prevention

When it happens

Trigger: validate_image(data) where int.from_bytes(data[:4], 'little') > 65536: either the file is not a wrapped chestnut image (random header bytes), or the firmware build genuinely outgrew the 64KB code region.

Common situations: Passing a raw ELF/bin or a different product's firmware whose first 4 bytes look like a huge length; a build regression (bloat, debug build) pushing the body over 64KB; byte-order confusion when constructing the wrapper by hand.

Related errors


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