commaai/openpilot · error · RomFallback
chestnut fell back to the ROM bootloader
Error message
chestnut fell back to the ROM bootloader
What it means
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.
Source
Thrown at openpilot/system/hardware/chestnut/flash.py:161
return fd
class Flash:
def __init__(self):
self.fd = -1
def close(self):
if self.fd >= 0:
os.close(self.fd)
self.fd = -1
def connect(self, timeout=5.0):
self.close()
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
path, vid_pid, product = find_chestnut()
if in_rom_bootloader(vid_pid, product):
raise RomFallback("chestnut fell back to the ROM bootloader")
if path is not None:
self.fd = claim_interface(path)
return
time.sleep(0.1)
raise RuntimeError(f"chestnut did not enumerate within {timeout:g}s")
def reg_write(self, addr, value):
fcntl.ioctl(self.fd, USBDEVFS_CONTROL,
Ctrl(0x40, 0xE5, addr & 0xFFFF, value & 0xFFFF, 0, 2000, None))
def reg_read(self, addr, length=1):
buf = (ctypes.c_ubyte * length)()
fcntl.ioctl(self.fd, USBDEVFS_CONTROL,
Ctrl(0xC0, 0xE4, addr & 0xFFFF, 0, length, 2000, ctypes.cast(buf, ctypes.c_void_p)))
return bytes(buf)
def write_buffer(self, data):
for i, value in enumerate(data):View on GitHub (pinned to 516ec1e682)
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
Example fix
# before
flash.connect() # RomFallback escapes and crashes the run
# after
try:
flash.connect()
except RomFallback:
rom_write(image, config) # ROM bootloader recovery, then reconnect Defensive patterns
Strategy: fallback
Validate before calling
from flash import find_chestnut, in_rom_bootloader
path, vid_pid, product = find_chestnut()
if in_rom_bootloader(vid_pid, product):
plan_rom_recovery() # prepare rom_write(image, config) path Type guard
from flash import RomFallback
def is_rom_fallback(e: BaseException) -> bool:
return isinstance(e, RomFallback) Try / catch
try:
flash.connect()
except RomFallback:
rom_write(image, config)
flash.connect() # device now runs real firmware Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- chestnut disappeared before recovery
- flash did not converge within {FLASH_BUDGET:g}s
- expected one chestnut, found {len(found)}
- chestnut did not re-enumerate after reset
- ROM flash command {cdb[0]:02x} {cdb[1]:02x} failed
AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15).
Data as JSON: /api/errors/1d669de1256b142e.
Report an issue: GitHub.