{"record":{"id":"bb66d1b1fcec970a","repo":"commaai/openpilot","slug":"invalid-wrapped-firmware-length-or-magic","errorCode":null,"errorMessage":"invalid wrapped firmware length or magic","messagePattern":"invalid wrapped firmware length or magic","errorType":"console","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"openpilot/system/hardware/chestnut/flash.py","lineNumber":257,"sourceCode":"    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\n  while True:\n    attempt += 1","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/system/hardware/chestnut/flash.py#L239-L275","documentation":"ValueError from validate_image(): the file's total length does not equal declared_body_length + 10, or the magic byte at offset 4+body_len is not 0xA5. Together these prove the file was truncated, padded, or is not a wrapped chestnut image at all. The length check runs first, so a bad length masks the magic check.","triggerScenarios":"validate_image(data) where len(data) != body_len + 10 (truncated download, extra trailing bytes, wrong file) or where data[4+body_len] != 0xA5 (magic marker missing - the wrapper was not created by the standard packaging step).","commonSituations":"Interrupted download or partial write of firmware_wrapped.bin; a newline or CRLF appended to the binary (e.g. text-mode transfer); passing a raw firmware bin that lacks the 10-byte wrapper; a stale wrapper format from an older packaging script without the magic byte.","solutions":["Verify the size math: len(file) must be exactly int.from_bytes(file[:4],'little') + 10; if off, re-transfer the file in binary mode","Regenerate the wrapped image with the project's packaging step rather than constructing it by hand","If hand-wrapping, place magic 0xA5, checksum byte, then CRC32 exactly at offsets body_len+4, body_len+5, body_len+6..9","Compare the sha256 of the artifact against the build's recorded hash to detect transfer corruption"],"exampleFix":"# canonical layout\n# [0:4] u32le body_len\n# [4:4+body_len] body\n# [4+body_len] 0xA5\n# [5+body_len] sum(body) & 0xFF\n# [6+body_len:10+body_len] crc32(body) u32le\nassert len(wrapped) == struct.unpack_from('<I', wrapped)[0] + 10","handlingStrategy":"validation","validationCode":"import struct\n\ndef wrapper_framing_ok(data: bytes) -> bool:\n    if len(data) < 10:\n        return False\n    body_len = struct.unpack_from('<I', data)[0]\n    return len(data) == body_len + 10 and data[4 + body_len] == 0xA5","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Transfer firmware in binary mode only (no ASCII-mode FTP, no text editors)","Verify the sha256 of artifacts against the build manifest before flashing","Regenerate wrappers only with the project's packaging script"],"tags":["firmware","validation","file-format","corruption"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}