commaai/openpilot · critical · RuntimeError

ROM flash command {cdb[0]:02x} {cdb[1]:02x} failed

Error message

ROM flash command {cdb[0]:02x} {cdb[1]:02x} failed

What it means

RuntimeError from the cmd() helper inside rom_write(): a SCSI BOT (Bulk-Only Transport) command sent to the ROM bootloader returned a Command Status Wrapper whose signature was not 'USBS' or whose status byte (csw[12]) was non-zero - the bootloader rejected or failed the vendor command. The CDB bytes in the message identify the failing recovery step (e.g. 'e3 50' writes firmware block 0, 'e8 51' finalizes).

Source

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

    buf = ctypes.create_string_buffer(bytes(payload), len(payload))
    fcntl.ioctl(fd, USBDEVFS_BULK, Bulk(ep, len(payload), timeout, ctypes.cast(buf, ctypes.c_void_p)))
    return buf.raw

  def cmd(cdb, data=b"", timeout=30000):
    nonlocal tag
    tag += 1
    bulk(0x02, struct.pack("<IIIBBB16s", 0x43425355, tag, len(data), 0, 0, len(cdb), cdb), timeout)
    if data:
      bulk(0x02, data, timeout)
    try:
      csw = bulk(0x81, bytes(13), timeout)
    except OSError as e:
      if e.errno != errno.EPIPE:
        raise
      fcntl.ioctl(fd, USBDEVFS_CLEAR_HALT, struct.pack("I", 0x81))
      csw = bulk(0x81, bytes(13), timeout)
    if csw[:4] != b"USBS" or csw[12] != 0:
      raise RuntimeError(f"ROM flash command {cdb[0]:02x} {cdb[1]:02x} failed")

  print("recovering from the ROM bootloader", flush=True)
  try:
    cmd(struct.pack(">BBB12x", 0xE1, 0x50, 0), config[:0x80])
    cmd(struct.pack(">BBB12x", 0xE1, 0x50, 1), config[0x80:])
    cmd(struct.pack(">BBI", 0xE3, 0x50, min(len(image), 0xFF00)), image[:0xFF00])
    if len(image) > 0xFF00:
      cmd(struct.pack(">BBI", 0xE3, 0xD0, len(image) - 0xFF00), image[0xFF00:])
    cmd(struct.pack(">BB13x", 0xE8, 0x51))
  finally:
    os.close(fd)
  print("recovery flash done", flush=True)


def vbus_write(value):
  try:
    with open(VBUS_PATH, "w") as f:
      f.write(value + "\n")

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Re-run the full recovery - ROM commands rewrite from the start, and a retry with a stable link usually succeeds
  2. Verify the image with validate_image() before recovery so the ROM never gets malformed lengths or data
  3. Move to a direct, high-quality USB connection; recovery uses 30s bulk timeouts, and hubs and long cables are the classic failure source
  4. If the same CDB fails deterministically across retries, the flash chip itself is failing in ROM mode - hardware replacement is the remaining option
Defensive patterns

Strategy: retry

Validate before calling

from flash import validate_image, find_chestnut

validate_image(image)                    # reject malformed images before ROM mode
assert find_chestnut()[0] is not None    # device present before recovery

Try / catch

try:
    rom_write(image, config)
except RuntimeError as e:
    if 'ROM flash command' in str(e):
        stabilize_link()          # reseat cable, direct port
        rom_write(image, config)  # full restart is safe - image rewritten from scratch

Prevention

When it happens

Trigger: rom_write()'s sequence: cmd(0xE1,0x50,...) writes config pages, cmd(0xE3,0x50/0xD0,...) writes firmware blocks, cmd(0xE8,0x51) finalizes. Any of these returning a failed CSW raises - caused by corrupt bulk data on a flaky link, a device-side flash write error, a protocol stall the CLEAR_HALT retry did not clear, or malformed image lengths in the CDB.

Common situations: Interrupted or corrupt bulk transfer on a bad cable during ROM recovery; a modified script sending chunks longer than the 0xFF00 split the ROM command accepts; flash chip hardware fault; commands sent out of order after a partial earlier failure.

Related errors


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