{"record":{"id":"7d1cdf8d7acf13c8","repo":"commaai/openpilot","slug":"write-failed-e","errorCode":null,"errorMessage":"write failed: {e}","messagePattern":"write failed: (.+?)","errorType":"exception","errorClass":"SerialException","httpStatus":null,"severity":"error","filePath":"openpilot/common/serial.py","lineNumber":173,"sourceCode":"      if chunk == b\"\\n\":\n        return bytes(buf)\n\n  def write(self, data: bytes) -> int:\n    self._ensure_open()\n    if not data:\n      return 0\n    view = memoryview(data)\n    total = 0\n    while total < len(data):\n      try:\n        n = os.write(self._fd, view[total:])\n      except InterruptedError:\n        continue\n      except OSError as e:\n        if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK):\n          select.select([], [self._fd], [], None)\n          continue\n        raise SerialException(e.errno, f\"write failed: {e}\") from e\n      if n == 0:\n        raise SerialException(\"write returned 0\")\n      total += n\n    return total\n\n  def flush(self) -> None:\n    self._ensure_open()\n    termios.tcdrain(self._fd)\n\n  def reset_input_buffer(self) -> None:\n    self._ensure_open()\n    termios.tcflush(self._fd, termios.TCIFLUSH)\n\n  def reset_output_buffer(self) -> None:\n    self._ensure_open()\n    termios.tcflush(self._fd, termios.TCOFLUSH)\n\n  def _close_fd(self) -> None:","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/serial.py#L155-L191","documentation":"Raised by Serial.write when os.write on the serial fd fails with an OSError other than EAGAIN/EWOULDBLOCK (which are handled by select+retry) or InterruptedError. Like the read path, it means the tty channel itself is failing, not just busy.","triggerScenarios":"Calling write() after device unplug (EIO/ENODEV), writing to a closed fd (EBADF), or the tty driver rejecting the write due to hardware flow control being stuck (device not asserting CTS when CRTSCTS is enabled).","commonSituations":"Peripheral power-cycled or unplugged while a writer thread is streaming, full hardware FIFO with no reader on the device side, flow-control mismatch between endpoints.","solutions":["Catch SerialException around writes and reopen the port on failure","Check that the peripheral is powered and the USB enumeration is intact (dmesg)","If flow control is enabled, confirm the peer drives CTS or disable CRTSCTS on the Serial config"],"exampleFix":"// before\nser.write(data)\n\n// after\ntry:\n  ser.write(data)\nexcept SerialException as e:\n  print(f\"serial write failed: {e}, reopening\")\n  ser.close()\n  ser = Serial(devpath, baudrate)\n  ser.write(data)","handlingStrategy":"try-catch","validationCode":"import os\n\ndef can_write(devpath: str) -> bool:\n    try:\n        fd = os.open(devpath, os.O_WRONLY | os.O_NONBLOCK)\n    except OSError:\n        return False\n    os.close(fd)\n    return True","typeGuard":null,"tryCatchPattern":"from common.serial import SerialException\ntry:\n    ser.write(data)\nexcept SerialException as e:\n    ser.close()\n    ser = Serial(devpath, baudrate)\n    ser.write(data)","preventionTips":["Confirm the peripheral stays powered during long write sessions","Match flow-control settings (rtscts) with the peer device","Wrap writers in a reconnect loop rather than assuming the fd stays valid"],"tags":["serial","hardware","io","usb"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}