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 pyserialVerify 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 $USERLog 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/ttyUSB0Permanent udev rule (example for FTDI adapters)
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", MODE="0666"Reload with sudo udevadm control --reload-rules && sudo udevadm trigger.
- Right-click your terminal and select "Run as administrator"
- Check Device Manager for missing drivers under "COM & LPT"
- Common driver downloads:
- FTDI: ftdichip.com/drivers
- CH340: search "CH341SER driver"
- CP210x: Silicon Labs VCP drivers
- System Preferences, Security & Privacy, Privacy tab, Full Disk Access
- Add Terminal (or your IDE) to the allowed list
ls -l /dev/cu.* # check port ownershipLog 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 directoryThe 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 SPUSBDataTypeTimeout 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.1Read 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 0Safe 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 busyAnother process has the port open.
# Find which process holds the port
sudo lsof /dev/ttyUSB0
# Force-release (Linux)
sudo fuser -k /dev/ttyUSB0Buffer 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 rateDiagnostic 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
| Category | Check |
|---|---|
| Install | pip install pyserial (not serial). Import as import serial. |
| Permissions | Linux: sudo usermod -a -G dialout $USER, then re-login. |
| Port name | Run serial.tools.list_ports.comports() to find the right one. |
| Baud rate | Must match on both ends exactly. |
| Timeout | Set timeout=1 or higher. None blocks forever. |
| Encoding | Decode with errors='replace' to avoid crashes on binary data. |
| Buffers | Call reset_input_buffer() before expecting a response. |
| Cable | Try a different USB cable. Charge-only cables have no data lines. |
Getting Help
If these solutions don't resolve your issue:
- Run the diagnostic script above
- Search the PySerial GitHub issues
- Post on Stack Overflow with the
pyserialtag, including your platform, PySerial version, and minimal reproduction code