commaai/openpilot · error · SerialException

could not open port {self._port}: {e}

Error message

could not open port {self._port}: {e}

What it means

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.

Source

Thrown at openpilot/common/serial.py:74

  @property
  def dtr(self) -> bool:
    return self._dtr

  @dtr.setter
  def dtr(self, value: bool) -> None:
    self._dtr = bool(value)
    if self._fd >= 0:
      self._set_line(TIOCM_DTR, _TIOCM_DTR, self._dtr)

  def open(self) -> None:
    if self._fd >= 0:
      return
    try:
      self._fd = os.open(self._port, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
    except OSError as e:
      self._fd = -1
      raise SerialException(e.errno, f"could not open port {self._port}: {e}") from e

    try:
      if self._exclusive:
        try:
          fcntl.flock(self._fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except OSError as e:
          raise SerialException(e.errno, f"could not exclusively lock port {self._port}: {e}") from e

      self._configure()

      # When not using hardware DSR/DTR handshaking, drive lines ourselves.
      if not self._dsrdtr:
        try:
          self._set_line(TIOCM_DTR, _TIOCM_DTR, self._dtr)
          if not self._rtscts:
            self._set_line(TIOCM_RTS, _TIOCM_RTS, True)
        except OSError as e:
          if e.errno not in (errno.EINVAL, errno.ENOTTY):

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Check the port exists (ls /dev/ttyUSB* /dev/ttyACM*) and matches the device actually present
  2. Fix permissions: add user to dialout group or adjust udev rules
  3. Retry open with a short delay at startup — the kernel may not have created the node yet
Defensive patterns

Strategy: retry

Validate before calling

import os

def port_ready(port: str) -> bool:
    return os.path.exists(port) and os.access(port, os.O_RDWR)

Try / catch

for _ in range(10):
    try:
        ser.open()
        break
    except SerialException:
        time.sleep(0.5)

Prevention

When it happens

Trigger: open() on /dev/ttyUSB*, /dev/ttyACM*, or a socat/ptsy path that does not exist, is permission-denied, or is locked by another process.

Common situations: 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.

Related errors


AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15). Data as JSON: /api/errors/dd03ffaaf00f813c. Report an issue: GitHub.