{"record":{"id":"b827f3a8a39ca243","repo":"commaai/openpilot","slug":"chestnut-disappeared-before-recovery","errorCode":null,"errorMessage":"chestnut disappeared before recovery","messagePattern":"chestnut disappeared before recovery","errorType":"console","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"openpilot/system/hardware/chestnut/flash.py","lineNumber":350,"sourceCode":"  except FileExistsError as e:\n    backup = open(path, \"rb\").read()\n    if len(backup) != 0x100:\n      raise RuntimeError(f\"invalid config backup: {path}\") from e\n    if backup != data:\n      print(f\"restoring config from {path}\", flush=True)\n    return backup\n  with os.fdopen(fd, \"wb\") as f:\n    f.write(data)\n    f.flush()\n    os.fsync(f.fileno())\n  return data\n\n\ndef rom_write(image, config):\n  # the ROM bootloader implements only the BOT protocol, and requires a port reset before bulk transfers\n  path, _, _ = find_chestnut()\n  if path is None:\n    raise RuntimeError(\"chestnut disappeared before recovery\")\n  unbind_drivers(path)\n  fd = open_device(path)\n  try:\n    fcntl.ioctl(fd, USBDEVFS_RESET)\n  finally:\n    os.close(fd)\n  time.sleep(3)\n  path, _, _ = find_chestnut()\n  if path is None:\n    raise RuntimeError(\"chestnut did not re-enumerate after reset\")\n  fd = claim_interface(path, setup=True)\n  for ep in (0x02, 0x81):\n    fcntl.ioctl(fd, USBDEVFS_CLEAR_HALT, struct.pack(\"I\", ep))\n  tag = 0\n\n  def bulk(ep, payload, timeout):\n    buf = ctypes.create_string_buffer(bytes(payload), len(payload))\n    fcntl.ioctl(fd, USBDEVFS_BULK, Bulk(ep, len(payload), timeout, ctypes.cast(buf, ctypes.c_void_p)))","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/system/hardware/chestnut/flash.py#L332-L368","documentation":"RuntimeError at the top of rom_write(): the tool entered ROM-bootloader recovery but find_chestnut() now returns None - the device, which moments ago matched a ROM VID:PID (174c:2464/2463), has vanished from the USB bus before the recovery transfer could start. Recovery cannot proceed without a live ROM-bootloader endpoint.","triggerScenarios":"rom_write() called right after RomFallback was detected, but between detection and this scan the device disconnected: cable moved, enclosure lost power, VBUS dropped, or the device hard-crashed out of the bootloader.","commonSituations":"Loose USB-C connection jostled during recovery prep; power negotiation hiccup on the port; a hub dropping the device; enclosure powered from a marginal source; the ROM bootloader resetting itself once more after enumerating.","solutions":["Check lsusb / /sys/bus/usb/devices for 174c:2464 - if absent, reseat cable and enclosure, wait for re-enumeration, re-run the tool","Use a direct, well-seated connection; avoid hubs and marginal cables for recovery flashing","Check VBUS regulation (/sys/kernel/debug/regulator/smb2-vbus/enable on the intended platform) if the enclosure is bus-powered","Retry the tool end-to-end - ROM recovery is idempotent and rewrites the whole image"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"from flash import find_chestnut\n\nif find_chestnut()[0] is None:\n    raise SystemExit('device absent - reseat before starting ROM recovery')","typeGuard":null,"tryCatchPattern":"try:\n    rom_write(image, config)\nexcept RuntimeError as e:\n    if 'disappeared' in str(e):\n        reseat_device(); rom_write(image, config)  # idempotent, safe to restart","preventionTips":["Physically secure cables before starting recovery","Verify the ROM device is present in lsusb right before invoking recovery","Recovery is restartable - never panic-abort mid-recovery; let it retry"],"tags":["usb","recovery","bootloader","enumeration","hardware"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}