commaai/openpilot · error · RuntimeError

bundled firmware is , expected version

Error message

bundled firmware is {expected_product!r}, expected version {expected_version}

What it means

Raised by flash_chestnut() when the caller passes an expected_version argument but the product string embedded in the bundled firmware image does not equal 'custom {expected_version}-CLEAN'. It is a pre-flight sanity check that runs before any hardware is touched, comparing image_product(image) against the version you claimed. The firmware bundle on disk and the version argument you passed disagree, so the flash aborts to avoid writing an unexpected build.

Solutions

  1. Re-run without the version argument to flash whatever is bundled: sudo python flash.py
  2. If you know the bundled version, pass exactly that hash: sudo python flash.py <correct-version>
  3. If the bundle is stale, restore the correct firmware file at FIRMWARE_PATH (git checkout / re-download) and retry with the expected version
  4. Verify what the bundle actually contains by calling image_product(FIRMWARE_PATH.read_bytes()) and compare to 'custom {version}-CLEAN'

Example fix

# before
flash_chestnut(expected_version="abc123")  # bundle has a different build

# after
prod = image_product(FIRMWARE_PATH.read_bytes())
print(prod)  # e.g. 'custom def456-CLEAN'
flash_chestnut(expected_version="def456")
Defensive patterns

Strategy: validation

Validate before calling

from openpilot.system.hardware.chestnut.flash import FIRMWARE_PATH, image_product, validate_image
image = FIRMWARE_PATH.read_bytes()
product = image_product(image)  # e.g. 'custom abc123-CLEAN'
expected = f"custom {args.version}-CLEAN"
assert args.version is None or product == expected, f"bundle={product!r} requested={expected!r}"

Try / catch

try:
    flash_chestnut(expected_version=ver, force=force)
except RuntimeError as e:
    if 'bundled firmware is' in str(e):
        print(f"version mismatch: {e}; re-run with the printed product's hash")
        raise SystemExit(2)
    raise

Prevention

When it happens

Trigger: Running 'python flash.py <version>' where <version> does not match the product string baked into FIRMWARE_PATH; rebuilding/replacing the bundled firmware image without updating the CLI argument; passing a full product string instead of just the version hash.

Common situations: Version skew after a partial checkout or stale firmware bundle; CI passing the release version while the working tree carries a locally built firmware; typo in the version hash on the command line.

Related errors


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

Appendix: source

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

        print(f"chestnut re-enumerated with {product!r}, firmware activates on its next power cycle", flush=True)
      return
    time.sleep(0.2)
  print("chestnut did not re-enumerate, firmware activates on its next power cycle", flush=True)


def defer_signal(signum, _frame):
  # writing from a handler must not reenter a print already in progress
  os.write(1, f"signal {signum} deferred until the chestnut is powered back up\n".encode())


def flash_chestnut(expected_version=None, force=False):
  global _deadline

  image = FIRMWARE_PATH.read_bytes()
  validate_image(image)
  expected_product = image_product(image)
  if expected_version is not None and expected_product != f"custom {expected_version}-CLEAN":
    raise RuntimeError(f"bundled firmware is {expected_product!r}, expected version {expected_version}")

  path, vid_pid, product = find_chestnut()
  if path is None:
    print("no chestnut connected", flush=True)
    return
  if product == expected_product and not force:
    print(f"chestnut firmware is up to date ({expected_product})", flush=True)
    return

  _deadline = time.monotonic() + FLASH_BUDGET
  for pm_path in PM_PATHS:
    disable_runtime_pm(pm_path)

  previous = {sig: signal.signal(sig, defer_signal) for sig in (signal.SIGINT, signal.SIGTERM, signal.SIGHUP)}
  try:
    if in_rom_bootloader(vid_pid, product):
      if not recover_from_rom(image, expected_product):
        return

View on GitHub (pinned to 516ec1e682)