{"record":{"id":"dd03ffaaf00f813c","repo":"commaai/openpilot","slug":"could-not-open-port-self-port-e","errorCode":null,"errorMessage":"could not open port {self._port}: {e}","messagePattern":"could not open port (.+?): (.+?)","errorType":"exception","errorClass":"SerialException","httpStatus":null,"severity":"error","filePath":"openpilot/common/serial.py","lineNumber":74,"sourceCode":"\n  @property\n  def dtr(self) -> bool:\n    return self._dtr\n\n  @dtr.setter\n  def dtr(self, value: bool) -> None:\n    self._dtr = bool(value)\n    if self._fd >= 0:\n      self._set_line(TIOCM_DTR, _TIOCM_DTR, self._dtr)\n\n  def open(self) -> None:\n    if self._fd >= 0:\n      return\n    try:\n      self._fd = os.open(self._port, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)\n    except OSError as e:\n      self._fd = -1\n      raise SerialException(e.errno, f\"could not open port {self._port}: {e}\") from e\n\n    try:\n      if self._exclusive:\n        try:\n          fcntl.flock(self._fd, fcntl.LOCK_EX | fcntl.LOCK_NB)\n        except OSError as e:\n          raise SerialException(e.errno, f\"could not exclusively lock port {self._port}: {e}\") from e\n\n      self._configure()\n\n      # When not using hardware DSR/DTR handshaking, drive lines ourselves.\n      if not self._dsrdtr:\n        try:\n          self._set_line(TIOCM_DTR, _TIOCM_DTR, self._dtr)\n          if not self._rtscts:\n            self._set_line(TIOCM_RTS, _TIOCM_RTS, True)\n        except OSError as e:\n          if e.errno not in (errno.EINVAL, errno.ENOTTY):","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/serial.py#L56-L92","documentation":"Serial.open() maps an OSError from os.open() on the device path to SerialException. Typical errno values: ENOENT (device node missing), EACCES (no permission), EBUSY (opened exclusively elsewhere). The message includes the port path and the OS error string.","triggerScenarios":"open() on /dev/ttyUSB*, /dev/ttyACM*, or a socat/ptsy path that does not exist, is permission-denied, or is locked by another process.","commonSituations":"Wrong device path after replug (ttyUSB0 became ttyUSB1); user not in dialout group; udev not created the node yet at open time; another process holds the port.","solutions":["Check the port exists (ls /dev/ttyUSB* /dev/ttyACM*) and matches the device actually present","Fix permissions: add user to dialout group or adjust udev rules","Retry open with a short delay at startup — the kernel may not have created the node yet"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import os\n\ndef port_ready(port: str) -> bool:\n    return os.path.exists(port) and os.access(port, os.O_RDWR)","typeGuard":null,"tryCatchPattern":"for _ in range(10):\n    try:\n        ser.open()\n        break\n    except SerialException:\n        time.sleep(0.5)","preventionTips":["Add user to dialout group; verify udev rules","Use stable device paths (by-id) instead of /dev/ttyUSB0","Retry open briefly at startup while the kernel creates the node"],"tags":["serial","io","device-access"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}