OSError: [Errno 5] Input/output error (tested fix)

OSError: [Errno 5] Input/output error is the OS reporting that a low-level read or write failed. Most often a terminal (pty) went away, but it can also be failing hardware. We reproduced the pty case in Python 3.13 and tested the fix.

1. What Errno 5 is

import errno, os
print(errno.EIO, errno.errorcode[5], os.strerror(5))

Output:

5 EIO Input/output error

EIO is the operating system saying a low-level read or write failed. Python only passes it on. The common causes: a pseudo-terminal (pty) whose other side has closed, a process in the background reading from or writing to a terminal it no longer controls (for example after nohup, & or a closed SSH session), and real hardware trouble: a failing disk, an unplugged USB drive or SD card, or a dropped network mount.

2. Reproduced: reading a pty after the other side closes

import os, pty
master, slave = pty.openpty()
os.write(slave, b"hello\n")
os.close(slave)                 # the "terminal" side goes away
print(os.read(master, 100))     # buffered data still arrives
try:
    os.read(master, 100)        # nothing left and no writer
except OSError as e:
    print(type(e).__name__, e.errno, e)

Output:

b'hello\r\n'
OSError 5 [Errno 5] Input/output error

The buffered data still arrives (note the \n became \r\n: the terminal driver translates newlines). Once it is drained and no one holds the other end, Linux raises [Errno 5] instead of returning b"" like a pipe would. This is what pexpect-style code and pty.spawn wrappers hit when the child exits.

3. Fix for pty readers: treat EIO as end of output

import os, pty, subprocess
master, slave = pty.openpty()
p = subprocess.Popen(["echo", "done"], stdout=slave, stderr=slave)
os.close(slave)
p.wait()
out = b""
while True:
    try:
        chunk = os.read(master, 1024)
    except OSError as e:
        if e.errno == 5:        # EIO == child closed the pty: treat as EOF
            break
        raise
    if not chunk:
        break
    out += chunk
print(out)

Output:

b'done\r\n'

Catch OSError, check e.errno == errno.EIO (5), and stop reading. Re-raise anything else.

4. The other causes (not reproduced here)

We did not reproduce these three (they need a real terminal session or failing hardware); the advice is the standard diagnosis. Related: OSError errno codes list and [Errno 9] Bad file descriptor.

Frequently asked questions

What causes [Errno 5] Input/output error in Python?

A pseudo-terminal whose other side closed, a background process using a terminal it lost, or a disk, USB or network-mount failure.

How do I fix Errno 5 when reading from a pty?

Catch OSError, check e.errno == errno.EIO and treat it as end of output.

How do I fix Errno 5 for a background script?

Redirect stdin from /dev/null and output to a log file, or run it under systemd, tmux or screen.

Written with AI assistance. Measured on 2026-10-22 on Debian with Python 3.13.5: errno 5 name and message, reading a pty master after the slave closes, and an EIO-as-EOF read loop around a subprocess. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.