commaai/openpilot · error · RuntimeError

expected one chestnut, found {len(found)}

Error message

expected one chestnut, found {len(found)}

What it means

RuntimeError from find_chestnut() in the chestnut flasher when more than one USB device matches the known VID:PID sets (normal or ROM bootloader IDs). The flash logic assumes exactly one candidate device; with several, it cannot know which to flash, so it aborts before touching anything.

Source

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

  _fields_ = [("ep", ctypes.c_uint), ("len", ctypes.c_uint),
              ("timeout", ctypes.c_uint), ("data", ctypes.c_void_p)]


class RomFallback(Exception):
  pass


def find_chestnut():
  found = []
  for d in glob.glob("/sys/bus/usb/devices/*"):
    try:
      vid_pid = (open(d + "/idVendor").read().strip(), open(d + "/idProduct").read().strip())
      if vid_pid in VID_PIDS + ROM_VID_PIDS:
        found.append((d, vid_pid, open(d + "/product").read().strip()))
    except OSError:
      pass
  if len(found) > 1:
    raise RuntimeError(f"expected one chestnut, found {len(found)}")
  return found[0] if found else (None, None, None)


def in_rom_bootloader(vid_pid, product):
  # the ROM bootloader reports the config page strings, or its own when the config page is lost
  return vid_pid in ROM_VID_PIDS or product == ROM_PRODUCT or (product or "").startswith("AS2462")


def disable_runtime_pm(path):
  control = os.path.join(path, "power/control")
  if not os.path.exists(control):
    return
  with open(control, "w") as f:
    f.write("on\n")
  if open(control).read().strip() != "on":
    raise RuntimeError(f"could not disable USB runtime PM: {control}")
  delay = os.path.join(path, "power/autosuspend_delay_ms")
  if os.path.exists(delay):

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Unplug all but the single chestnut device you intend to flash and rerun
  2. Power off/remove the extra unit — including one stuck in ROM bootloader mode from a prior failed flash
  3. List matches first via lsusb (compare VID:PID) to identify the duplicate

Example fix

// before
# two chestnut boards plugged in
flash_chestnut()  # RuntimeError: expected one chestnut, found 2

// after
# unplug extra board, keep only target
flash_chestnut()
Defensive patterns

Strategy: validation

Validate before calling

from openpilot.system.hardware.chestnut.flash import find_chestnut, VID_PIDS, ROM_VID_PIDS

def exactly_one_chestnut() -> bool:
    path, vid_pid, product = find_chestnut()
    return path is not None and not multiple_candidates()

Prevention

When it happens

Trigger: Having two chestnut boards (or a second device that shares the AS2462-based VID:PID, including one already sitting in ROM bootloader mode alongside a normally enumerated one) plugged in when the flasher scans /sys/bus/usb/devices.

Common situations: A bench with multiple units under test, a device half-flashed from a previous run enumerating in ROM mode while a second unit is attached, or unrelated hardware reusing the same chip.

Related errors


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