{"record":{"id":"ee952845ad8bda7d","repo":"commaai/openpilot","slug":"wrapped-firmware-body-exceeds-max-code-size-byte","errorCode":null,"errorMessage":"wrapped firmware body exceeds {MAX_CODE_SIZE} bytes","messagePattern":"wrapped firmware body exceeds (.+?) bytes","errorType":"console","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"openpilot/system/hardware/chestnut/flash.py","lineNumber":255,"sourceCode":"\n  def erase_sector(self, addr):\n    self.write_enable()\n    self.transaction(0x20, addr)\n    self.wait_write_done()\n\n  def program(self, addr, data):\n    self.write_buffer(data + bytes((-len(data)) % 4))\n    self.write_enable()\n    self.transaction(0x02, addr, len(data), mode=1)\n    self.wait_write_done()\n\n\ndef validate_image(data):\n  if len(data) < 10:\n    raise ValueError(\"wrapped firmware is too short\")\n  body_len = int.from_bytes(data[:4], \"little\")\n  if body_len > MAX_CODE_SIZE:\n    raise ValueError(f\"wrapped firmware body exceeds {MAX_CODE_SIZE} bytes\")\n  if len(data) != body_len + 10 or data[4 + body_len] != 0xA5:\n    raise ValueError(\"invalid wrapped firmware length or magic\")\n  body = data[4:4 + body_len]\n  if data[5 + body_len] != sum(body) & 0xFF:\n    raise ValueError(\"invalid wrapped firmware checksum\")\n  if data[6 + body_len:] != zlib.crc32(body).to_bytes(4, \"little\"):\n    raise ValueError(\"invalid wrapped firmware CRC\")\n\n\ndef image_product(image):\n  match = re.search(rb\"custom [0-9a-f]{8}-CLEAN\", image)\n  if match is None:\n    raise ValueError(\"no product string in wrapped firmware\")\n  return match.group().decode()\n\n\ndef reconnect(flash):\n  attempt = 0","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/system/hardware/chestnut/flash.py#L237-L273","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Confirm the file is the correct artifact: it must be the wrapped chestnut image produced by the matching build step, not a raw binary","If building your own: reduce firmware size below 64KB (strip, optimize for size, remove dead code) and re-wrap with a correct header","If hand-wrapping, write the header as struct.pack('<I', len(body)) and verify against the validate_image logic","Check for accidental concatenation or prepended garbage that shifts the header"],"exampleFix":"# after (correct wrap)\nbody = open('fw.bin','rb').read()\nassert len(body) <= 0x10000\nwrapped = struct.pack('<I', len(body)) + body + b'\\xa5' + bytes([sum(body) & 0xFF]) + zlib.crc32(body).to_bytes(4, 'little')","handlingStrategy":"validation","validationCode":"import struct\n\ndef body_len_ok(data: bytes) -> bool:\n    return len(data) >= 4 and struct.unpack_from('<I', data)[0] <= 0x10000","typeGuard":null,"tryCatchPattern":"try:\n    validate_image(data)\nexcept ValueError as e:\n    if 'exceeds' in str(e):\n        fail_build('firmware too large - trim before flashing')","preventionTips":["Add a size assertion to the firmware build so oversize images fail at build time","Use release/size-optimized builds for shipped firmware","Never flash raw binaries that were not produced by the wrapping step"],"tags":["firmware","validation","size-limit"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}