commaai/openpilot · error · ValueError
no product string in wrapped firmware
Error message
no product string in wrapped firmware
What it means
ValueError from image_product(): it greps the image for the ASCII marker 'custom XXXXXXXX-CLEAN' (8 hex chars, e.g. a git short SHA) to identify which build the firmware targets. If the regex finds no match, the image has no embedded product string and the tool cannot tell whether the image matches this device's expected product.
Source
Thrown at openpilot/system/hardware/chestnut/flash.py:268
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()
return
except (OSError, TimeoutError, RuntimeError) as e:
print(f"waiting for chestnut (attempt {attempt}): {e}", flush=True)
time.sleep(1)
def with_retries(flash, label, operation):View on GitHub (pinned to 516ec1e682)
Solutions
- Use the official wrapped firmware artifact from the matching openpilot build - it always embeds the product string
- If self-building, ensure the firmware source embeds the literal 'custom <8-hex-git-sha>-CLEAN' string and keeps it alive (used attribute or KEEP() in the linker script)
- Do not strip string sections from the firmware binary during packaging
- Only flash images built for this product line
Example fix
// firmware source must keep the string reachable __attribute__((used)) static const char g_product[] = "custom " GIT_SHORT_SHA "-CLEAN";
Defensive patterns
Strategy: validation
Validate before calling
import re
def has_product_string(image: bytes) -> bool:
return re.search(rb'custom [0-9a-f]{8}-CLEAN', image) is not None Prevention
- Build firmware with the product string compiled in and marked used/KEEP
- Only flash artifacts from the matching product build pipeline
- The packaging step should assert image_product() succeeds before publish
When it happens
Trigger: image_product(image) on a wrapped image whose body was built without the product/version string baked in - e.g. a raw vendor firmware, a locally compiled binary missing the version-string section, or a stripped build that dropped the literal string.
Common situations: Flashing a third-party or upstream ASM2464 firmware that never embeds openpilot's 'custom <sha>-CLEAN' string; building firmware with the version define omitted; a linker garbage-collection pass that dropped the string from the final binary.
Related errors
- expected one chestnut, found {len(found)}
- wrapped firmware is too short
- wrapped firmware body exceeds {MAX_CODE_SIZE} bytes
- invalid wrapped firmware length or magic
- invalid wrapped firmware checksum
AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15).
Data as JSON: /api/errors/828af4dd7f09b553.
Report an issue: GitHub.