{"record":{"id":"1d669de1256b142e","repo":"commaai/openpilot","slug":"chestnut-fell-back-to-the-rom-bootloader","errorCode":null,"errorMessage":"chestnut fell back to the ROM bootloader","messagePattern":"chestnut fell back to the ROM bootloader","errorType":"console","errorClass":"RomFallback","httpStatus":null,"severity":"error","filePath":"openpilot/system/hardware/chestnut/flash.py","lineNumber":161,"sourceCode":"  return fd\n\n\nclass Flash:\n  def __init__(self):\n    self.fd = -1\n\n  def close(self):\n    if self.fd >= 0:\n      os.close(self.fd)\n      self.fd = -1\n\n  def connect(self, timeout=5.0):\n    self.close()\n    deadline = time.monotonic() + timeout\n    while time.monotonic() < deadline:\n      path, vid_pid, product = find_chestnut()\n      if in_rom_bootloader(vid_pid, product):\n        raise RomFallback(\"chestnut fell back to the ROM bootloader\")\n      if path is not None:\n        self.fd = claim_interface(path)\n        return\n      time.sleep(0.1)\n    raise RuntimeError(f\"chestnut did not enumerate within {timeout:g}s\")\n\n  def reg_write(self, addr, value):\n    fcntl.ioctl(self.fd, USBDEVFS_CONTROL,\n                Ctrl(0x40, 0xE5, addr & 0xFFFF, value & 0xFFFF, 0, 2000, None))\n\n  def reg_read(self, addr, length=1):\n    buf = (ctypes.c_ubyte * length)()\n    fcntl.ioctl(self.fd, USBDEVFS_CONTROL,\n                Ctrl(0xC0, 0xE4, addr & 0xFFFF, 0, length, 2000, ctypes.cast(buf, ctypes.c_void_p)))\n    return bytes(buf)\n\n  def write_buffer(self, data):\n    for i, value in enumerate(data):","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/system/hardware/chestnut/flash.py#L143-L179","documentation":"RomFallback is raised by Flash.connect() when find_chestnut() reports a VID:PID or product string matching the ASM2464 ROM bootloader (174c:2464/174c:2463, 'USB 3.2 PCIe TinyEnclosure', or 'AS2462*'). It means the device lost (or never had) valid firmware in SPI flash, so it fell back to the mask-ROM bootloader. This is not a hard failure: the tool's main flow catches RomFallback and routes to rom_write() to reflash via the ROM's USB BOT protocol.","triggerScenarios":"Flash.connect() during initial enumeration, or reconnect() after an erase/program brick: the SPI contents are empty/corrupt, so the ASM2464 boots its ROM bootloader and enumerates as 174c:2464 with a usb-storage-compatible BOT interface. Also occurs on a brand-new enclosure with unprogrammed flash.","commonSituations":"First-time provisioning of a chestnut enclosure; recovery after a flash was interrupted mid-erase (sector erased, firmware not yet written); watchdog or power loss during programming; a device whose firmware region reads all 0xFF.","solutions":["Let the tool handle it: ensure the caller catches RomFallback and invokes rom_write(image, config) - the recovery path is built in","Verify the wrapped image is valid (validate_image) before recovery so rom_write does not reflash garbage","Check power/USB-C connection stability so the ROM-mode bulk transfers (30s timeouts) are not interrupted mid-recovery","If it keeps falling back after successful recovery, suspect failing SPI flash chip or bad VBUS/wiring"],"exampleFix":"# before\nflash.connect()  # RomFallback escapes and crashes the run\n\n# after\ntry:\n    flash.connect()\nexcept RomFallback:\n    rom_write(image, config)  # ROM bootloader recovery, then reconnect","handlingStrategy":"fallback","validationCode":"from flash import find_chestnut, in_rom_bootloader\n\npath, vid_pid, product = find_chestnut()\nif in_rom_bootloader(vid_pid, product):\n    plan_rom_recovery()  # prepare rom_write(image, config) path","typeGuard":"from flash import RomFallback\n\ndef is_rom_fallback(e: BaseException) -> bool:\n    return isinstance(e, RomFallback)","tryCatchPattern":"try:\n    flash.connect()\nexcept RomFallback:\n    rom_write(image, config)\n    flash.connect()  # device now runs real firmware","preventionTips":["Never treat RomFallback as fatal - it is the designed entry to recovery","Keep a valid wrapped image on hand before any erase/program session","Avoid interrupting the flasher mid-erase; that is the main cause of ROM fallback"],"tags":["usb","bootloader","recovery","firmware","hardware"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}