{"record":{"id":"5a5009c7233d14a3","repo":"commaai/openpilot","slug":"chestnut-is-in-use-stop-modeld-gpu-processes-befo","errorCode":null,"errorMessage":"chestnut is in use, stop modeld/GPU processes before flashing","messagePattern":"chestnut is in use, stop modeld/GPU processes before flashing","errorType":"console","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"openpilot/system/hardware/chestnut/flash.py","lineNumber":141,"sourceCode":"  finally:\n    os.close(fd)\n\n\ndef claim_interface(path, setup=False):\n  # unbind usb-storage, which binds to the ROM bootloader\n  disable_runtime_pm(path)\n  unbind_drivers(path)\n  fd = open_device(path)\n  try:\n    if setup:\n      fcntl.ioctl(fd, USBDEVFS_SETCONFIGURATION, struct.pack(\"I\", 1))\n    fcntl.ioctl(fd, USBDEVFS_CLAIMINTERFACE, struct.pack(\"I\", 0))\n    if setup:\n      fcntl.ioctl(fd, USBDEVFS_SETINTERFACE, struct.pack(\"II\", 0, 0))\n  except OSError as e:\n    os.close(fd)\n    if e.errno == errno.EBUSY:\n      raise RuntimeError(\"chestnut is in use, stop modeld/GPU processes before flashing\") from e\n    raise\n  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()","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/system/hardware/chestnut/flash.py#L123-L159","documentation":"Raised by claim_interface() in openpilot/system/hardware/chestnut/flash.py when the USBDEVFS_CLAIMINTERFACE (or SETCONFIGURATION/SETINTERFACE) ioctl returns EBUSY. It means another process currently holds the USB interface of the ASM2464 (chestnut) bridge, almost always the GPU driver stack (modeld) that uses the device in normal operation. The flasher refuses to share the device because EP0 control-register access during flashing would corrupt live GPU traffic.","triggerScenarios":"Calling Flash.connect() or rom_write() (both call claim_interface) while modeld or any process with the chestnut USB interface open is still running. EBUSY comes from the kernel when usbfs cannot claim interface 0 because another driver is bound or another usbfs fd holds a claim.","commonSituations":"Running the flasher on a live openpilot device without stopping manager/modeld first; a leftover process holding /dev/bus/usb open after a previous aborted flash; usb-storage still bound to the ROM bootloader interface.","solutions":["Stop the processes using the device: systemctl stop the openpilot service or pkill modeld (and anything holding /dev/bus/usb for VID 3801:0001 / add1:0001), then re-run the flasher","Find who holds the device with lsof / grep on /dev/bus/usb or fuser, and kill that process","If a kernel driver is still bound, echo the interface into the driver's unbind node (the script's unbind_drivers does this, but only for interfaces with a driver symlink) or unbind it manually and retry","As a last resort unplug/replug the chestnut enclosure to force a clean enumeration, then retry"],"exampleFix":"# before: flashing while modeld runs\nsudo python3 flash.py\n# RuntimeError: chestnut is in use...\n\n# after: stop users first\npkill modeld; sleep 2\nsudo python3 flash.py","handlingStrategy":"validation","validationCode":"import glob, os\n\ndef chestnut_users():\n    users = []\n    for d in glob.glob('/sys/bus/usb/devices/*'):\n        try:\n            vid = open(d + '/idVendor').read().strip()\n            pid = open(d + '/idProduct').read().strip()\n        except OSError:\n            continue\n        if (vid, pid) in (('3801', '0001'), ('add1', '0001'), ('174c', '2464'), ('174c', '2463')):\n            bus = int(open(d + '/busnum').read()); dev = int(open(d + '/devnum').read())\n            users.append(f'/dev/bus/usb/{bus:03d}/{dev:03d}')\n    return users  # pass each to lsof/fuser before flashing","typeGuard":null,"tryCatchPattern":"try:\n    flash.connect()\nexcept RuntimeError as e:\n    if 'in use' in str(e):\n        stop_modeld_and_retry()  # kill holders, then reconnect\n    raise","preventionTips":["Always stop modeld/openpilot services before running the flasher","Add a preflight step that runs fuser/lsof on the device node and aborts with a clear message","Never run two flasher instances concurrently"],"tags":["usb","hardware","ebusy","flashing","driver-conflict"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}