commaai/openpilot · error · ValueError
invalid wrapped firmware length or magic
Error message
invalid wrapped firmware length or magic
What it means
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.
Source
Thrown at openpilot/system/hardware/chestnut/flash.py:257
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
while True:
attempt += 1View on GitHub (pinned to 516ec1e682)
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
Example fix
# canonical layout
# [0:4] u32le body_len
# [4:4+body_len] body
# [4+body_len] 0xA5
# [5+body_len] sum(body) & 0xFF
# [6+body_len:10+body_len] crc32(body) u32le
assert len(wrapped) == struct.unpack_from('<I', wrapped)[0] + 10 Defensive patterns
Strategy: validation
Validate before calling
import struct
def wrapper_framing_ok(data: bytes) -> bool:
if len(data) < 10:
return False
body_len = struct.unpack_from('<I', data)[0]
return len(data) == body_len + 10 and data[4 + body_len] == 0xA5 Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- wrapped firmware is too short
- invalid wrapped firmware checksum
- invalid wrapped firmware CRC
- invalid config backup: {backup}
- expected one chestnut, found {len(found)}
AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15).
Data as JSON: /api/errors/bb66d1b1fcec970a.
Report an issue: GitHub.