PySerial
PySerialDocs

Common Errors

Fix PySerial errors fast. Solutions for permission denied, module not found, serial exceptions, and timeout issues on Windows, Linux, and macOS.

Fix PySerial errors quickly with these proven solutions.

ModuleNotFoundError: No module named 'serial'

ModuleNotFoundError: No module named 'serial'

The package name is pyserial, but you import it as serial. Installing the wrong package (serial) is the most common cause.

Remove the wrong package and install the right one

pip uninstall serial
pip install pyserial

Verify the import

import serial
print(f"PySerial version: {serial.__version__}")

Permission Denied

PermissionError: [Errno 13] Permission denied: '/dev/ttyUSB0'

This is the number one issue on Linux. The fix is simple but requires a logout/login.

Add your user to the dialout group

sudo usermod -a -G dialout $USER

Log out and back in (or run newgrp dialout for the current shell).

Verify

groups  # should list 'dialout'

Quick temporary fix for testing

sudo chmod 666 /dev/ttyUSB0

Permanent udev rule (example for FTDI adapters)

SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", MODE="0666"

Reload with sudo udevadm control --reload-rules && sudo udevadm trigger.

  1. Right-click your terminal and select "Run as administrator"
  2. Check Device Manager for missing drivers under "COM & LPT"
  3. Common driver downloads:
  1. System Preferences, Security & Privacy, Privacy tab, Full Disk Access
  2. Add Terminal (or your IDE) to the allowed list
ls -l /dev/cu.*  # check port ownership

Log serial data automatically

TofuPilot records test results from your PySerial scripts, tracks pass/fail rates, and generates compliance reports. Free to start.

SerialException: could not open port

serial.serialutil.SerialException: could not open port '/dev/ttyUSB0': [Errno 2] No such file or directory

The port name is wrong or the device is not connected.

Find available ports

import serial.tools.list_ports

ports = serial.tools.list_ports.comports()
if not ports:
    print("No serial ports found")
else:
    for port in ports:
        print(f"  {port.device}: {port.description}")
        if port.vid is not None:
            print(f"    VID:PID = {port.vid:04X}:{port.pid:04X}")

Platform-specific checks

ls /dev/ttyUSB* /dev/ttyACM*   # USB serial devices
dmesg | grep tty                # kernel messages for serial
[System.IO.Ports.SerialPort]::getportnames()
ls /dev/cu.*
system_profiler SPUSBDataType

Timeout Issues

Symptoms: read() returns empty bytes, program hangs, inconsistent data.

import serial

ser = serial.Serial('/dev/ttyUSB0', 9600)

# Blocking forever (dangerous, can hang your program)
ser.timeout = None

# Non-blocking (returns immediately, may be empty)
ser.timeout = 0

# Fixed timeout (recommended starting point)
ser.timeout = 2

# Inter-byte timeout for variable-length messages
ser.timeout = 5
ser.inter_byte_timeout = 0.1

Read with increasing timeout

def read_with_retry(ser, size, max_attempts=3):
    """Retry reads with progressively longer timeouts."""
    for attempt in range(max_attempts):
        ser.timeout = 1.0 + (attempt * 0.5)
        data = ser.read(size)
        if len(data) == size:
            return data
        print(f"Attempt {attempt + 1}: got {len(data)}/{size} bytes")
    return b''

Encoding/Decoding Errors

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0

Safe decoding

def safe_decode(data, encodings=('utf-8', 'ascii', 'latin-1')):
    """Try multiple encodings, fall back to ignoring errors."""
    for enc in encodings:
        try:
            return data.decode(enc)
        except UnicodeDecodeError:
            continue
    return data.decode('utf-8', errors='ignore')

raw = ser.read(100)
text = safe_decode(raw)

Identify binary vs. text data

def classify_data(data):
    """Return 'text', 'mixed', or 'binary' based on content."""
    try:
        text = data.decode('utf-8')
        if all(32 <= ord(c) <= 126 or c in '\r\n\t' for c in text):
            return 'text', text
        return 'mixed', text
    except UnicodeDecodeError:
        return 'binary', data.hex()

Arduino Reset on Connect

Arduino boards reset when a serial connection opens, causing a 1-2 second delay.

import serial
import time

def connect_arduino(port, baudrate=9600, reset_delay=2):
    """Open the port and wait for Arduino to finish resetting."""
    ser = serial.Serial(port, baudrate, timeout=1)
    time.sleep(reset_delay)
    ser.reset_input_buffer()
    return ser

ser = connect_arduino('/dev/ttyACM0')

Device Busy

SerialException: could not open port: [Errno 16] Device or resource busy

Another process has the port open.

# Find which process holds the port
sudo lsof /dev/ttyUSB0

# Force-release (Linux)
sudo fuser -k /dev/ttyUSB0

Buffer Overflow

Symptoms: missing data, corrupted messages.

# Drain excess data before starting
if ser.in_waiting > 4096:
    ser.reset_input_buffer()

# Read frequently enough to keep up with the data rate

Diagnostic Script

Save and run this to check your setup in one shot.

#!/usr/bin/env python3
"""Quick PySerial diagnostic. Run: python pyserial_diagnostic.py"""

import sys
import platform

def main():
    print(f"Platform: {platform.system()} {platform.release()}")
    print(f"Python:   {sys.version.split()[0]}")

    try:
        import serial
        print(f"PySerial: {serial.__version__}")
    except ImportError:
        print("PySerial: NOT INSTALLED (run: pip install pyserial)")
        return

    import serial.tools.list_ports
    ports = list(serial.tools.list_ports.comports())

    if not ports:
        print("\nNo serial ports found.")
        print("  - Check that your device is plugged in")
        print("  - Install USB drivers if needed")
        return

    print(f"\nFound {len(ports)} port(s):")
    ok = 0
    for p in ports:
        print(f"\n  {p.device}: {p.description}")
        if p.vid is not None:
            print(f"    VID:PID = {p.vid:04X}:{p.pid:04X}")
        try:
            s = serial.Serial(p.device, 9600, timeout=0.1)
            print(f"    Status: open OK, {s.in_waiting} bytes waiting")
            s.close()
            ok += 1
        except PermissionError:
            system = platform.system()
            fix = {
                "Linux": "sudo usermod -a -G dialout $USER",
                "Windows": "Run as administrator",
                "Darwin": "Check Security & Privacy settings",
            }.get(system, "Check permissions")
            print(f"    Status: PERMISSION DENIED ({fix})")
        except Exception as e:
            print(f"    Status: ERROR ({e})")

    print(f"\nResult: {ok}/{len(ports)} ports accessible")

if __name__ == "__main__":
    main()

Quick Fix Checklist

CategoryCheck
Installpip install pyserial (not serial). Import as import serial.
PermissionsLinux: sudo usermod -a -G dialout $USER, then re-login.
Port nameRun serial.tools.list_ports.comports() to find the right one.
Baud rateMust match on both ends exactly.
TimeoutSet timeout=1 or higher. None blocks forever.
EncodingDecode with errors='replace' to avoid crashes on binary data.
BuffersCall reset_input_buffer() before expecting a response.
CableTry a different USB cable. Charge-only cables have no data lines.

Getting Help

If these solutions don't resolve your issue:

  1. Run the diagnostic script above
  2. Search the PySerial GitHub issues
  3. Post on Stack Overflow with the pyserial tag, including your platform, PySerial version, and minimal reproduction code